Commit Graph

105 Commits

Author SHA1 Message Date
Celegans12 e1d4e699be feat(agc): implement primitive-ordered pixel shaders with fragment shader interlock
DecodeState and the draw precheck rejected DB_SHADER_CONTROL bit 16,
PRIMITIVE_ORDERED_PIXEL_SHADER (POPS), which runs the ordered section
of overlapping pixels' shaders in primitive order. The bit now reaches
the recompiler as a pixel stage field, and such a pixel shader declares
PixelInterlockOrderedEXT and runs its whole body between
OpBeginInvocationInterlockEXT and OpEndInvocationInterlockEXT; an
invocation that a BDA read fault kills ends the interlock first. The
POPS collision SGPRs read 0, so a title skips its POPS wait and runs
its per-collision loop once. An image_load still reads a sampled
binding, which misses an earlier overlapping primitive's image_store in
the same draw. The device enables VK_EXT_fragment_shader_interlock when
it has fragmentShaderPixelInterlock; without it the recompile throws,
as does a nonzero POPS_OVERLAP_NUM_SAMPLES. The field is part of the
recompile cache key, the draw key and the serialized request (version 10).
2026-10-08 11:18:46 +02:00
Michon 20e055c244 feat(agc): compute dispatches with scratch memory
A compute program with COMPUTE_PGM_RSRC2.SCRATCH_EN takes its per-lane private size from the AGC
shader header (scratch_size_dw_per_thread) instead of being refused. The size travels in
ShaderComputeStageInfo (cache key, request serialization version 10) to the translator, whose
scratch accesses already lower to a per-invocation Function array of that many dwords.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-08 10:22:40 +02:00
Adrià e705d430d6
Merge pull request #1139 from alfalfa-star/fix/agc-inert-pixel-stage
fix(agc): run draws whose pixel stage cannot run without its program
2026-10-08 10:20:09 +02:00
Adrià 8e22498c20
Merge pull request #1134 from alfalfa-star/fix/agc-mesh-unindexed-index-vsharp
fix(agc): bind a null index buffer to non-indexed mesh draws
2026-10-08 10:15:09 +02:00
Chad c17337b6d9 fix(agc): size CMASK by whole 1024x512 metablocks
A CMASK holds 4 KiB per 1024x512-pixel metablock, not one nibble per 8x8
tile of the target: 1920x1080 spans 0x6000 bytes, as titles clear it,
not 16200. The swizzled nibbles of the lower-right tiles lie past the
packed size, so the fast-clear check missed them and the expanded store
left them cleared.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 19:53:02 +13:00
Adrià 56f3da20e8
Merge pull request #1072 from alfalfa-star/feat/agc-cmask-fast-clear
feat(agc): render into CMASK fast-clear color targets
2026-10-08 08:32:04 +02:00
Adrià e9fecced17
Merge pull request #1086 from Celegans12/fix/agc-depth-bias-clamp-default
fix(agc): include PA_SU_POLY_OFFSET_CLAMP in the initial context state
2026-10-08 08:06:30 +02:00
alfalfa-star b5be685912 feat(agc): accept CMASK fast-clear DCC targets whose CMASK is expanded
A color target with both DCC and CB_COLOR_INFO.FAST_CLEAR keeps its fast
clear in the DCC keys and fills its CMASK with 0xF (expanded), as radv
does (radv_get_cmask_fast_clear_value) and as PPSA21567 does
(CB_COLOR_INFO 0x10042730, reported on #419). Such targets now decode;
their clear is materialized by the existing DCC path. A DCC target's
CMASK that is not all expanded throws.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 07:58:40 +02:00
alfalfa-star 61a61016d8 feat(agc): render into CMASK fast-clear color targets
Draws into a color target with CB_COLOR_INFO FAST_CLEAR (bit 13) were
rejected. The CMASK keeps one nibble per 8x8 tile: 0 means the tile is
fast-cleared and reads as CB_COLOR_CLEAR_WORD, 0xF means expanded (the
texels hold the color). The texture units and display scanout do not read
it, so a title runs a fast-clear eliminate pass before sampling or
flipping such a target.

DecodeColorBuffer now takes the CMASK address (CB_COLOR0_CMASK and
CB_COLOR0_CMASK_BASE_EXT) and the bytes one nibble per 8x8 tile spans.
Before a draw renders into the target, and in a fast-clear eliminate
pass, a CMASK whose nibbles are all 0 is materialized: the target is
filled with the clear texel (FillClear on its resident image, else
guest memory on the CPU) and the CMASK bytes are stored as expanded,
through the same GPU-ordered store as the DCC "uncompressed" keys
(0xFF either way). The result equals the draw followed by the eliminate
pass. An all-expanded CMASK changes nothing; a mixed one throws, as do
fast clears of DCC, mipmapped, 3D and array targets.

PPSA14632 (LEGO Horizon Adventures) fast-clears its two 3840x2160
display buffers through CMASK, so its final composite draw was dropped
on every frame and only black was presented.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 07:58:31 +02:00
Adrià 058dead176
Merge pull request #1058 from Celegans12/feat/agc-r8-srgb-color-target
feat(agc): implement 8 srgb color targets through rgba8 srgb proxies
2026-10-08 07:52:45 +02:00
Adrià 6c48acecb3
Merge pull request #285 from SP4C3B4R-8/feat/gds-guest-memory
feat(libSceAgcDriver): back the global data share with driver-owned guest memory
2026-10-07 23:00:32 +02:00
SP4C3B4R-8 a68b3481ab feat(libSceAgcDriver): back the global data share with driver-owned guest memory
Shader GDS accesses bind the same 64 KiB guest range that DMA_DATA packets
read and write, so both go through the existing CPU/GPU coherence tracking.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 22:01:04 +02:00
Michon 29aa275653 fix(agc): accept fragment Geometry and SampleRateShading only when the device enabled them
The validator takes the geometryShader and sampleRateShading enables from the
context (set where #295 enables them), so a device without them refuses the
draw instead of creating a module that needs features it never enabled.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-07 18:18:47 +02:00
Michon f3fd29db0d fix(agc): accept a fragment SampleMask output
Pixel shaders that export a coverage mask write gl_SampleMask, an
int[1] (or uint[1]) output. The validator rejected array interface
types; it now spells them elem[N] and accepts SampleMask as int[1] or
uint[1].

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-07 18:18:12 +02:00
Michon 78726f3836 fix(agc): fragment SampleId, Layer and FragDepth interfaces
The recompiler emits SampleId and Layer fragment inputs (pixel ancillary
data) and a FragDepth output with the DepthReplacing execution mode
(depth export), but the validator refused them, so those draws were
skipped. They are now accepted, as are the Geometry and SampleRateShading
capabilities those inputs need in fragment shaders. The device enables
both features when it has them.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-07 18:18:12 +02:00
alfalfa-star 98405e8f25 fix(agc): run draws whose pixel stage cannot run without its program
A depth-only pass can leave a stale pixel program address in
SPI_SHADER_PGM_LO/HI_PS while never setting the pixel registers it does
not need. The draw then failed with "missing register at DWORD 0x1b3"
(SPI_PS_INPUT_ENA), although the hardware never launches that program:
with no color written (CB_TARGET_MASK & CB_SHADER_MASK == 0), no depth,
stencil or mask export (SPI_SHADER_Z_FORMAT 0 and those enables of
DB_SHADER_CONTROL clear), and neither KILL_ENABLE, EXEC_ON_HIER_FAIL,
EXEC_ON_NOOP nor EXEC_IF_OVERLAPPED set, the pixel shader has no effect
and is not executed.

PixelProgramUnset becomes PixelProgramSkipped: true for a zero program
address as before, and for such an inert pixel stage. Both use the
driver's null pixel program; the precheck and the decode agree.

PPSA14632 (LEGO Horizon Adventures) issues an HTILE expand this way
(DB_RENDER_CONTROL DEPTH/STENCIL_COMPRESS_DISABLE, CB disabled, depth
test and writes off) once per run.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 15:31:39 +02:00
alfalfa-star 5822c26b59 fix(agc): bind a null index buffer to non-indexed mesh draws
A non-indexed mesh draw (DRAW_INDEX_AUTO, or a non-indexed indirect
record) gave the mesh program's hidden index buffer V# (user words 4..7)
a 4-byte range at the program's own code address, so the descriptor had
a guest address although the prologue never loads through it (the load
is predicated on the draw's index size). That range is bound from live
guest memory. When the program also reads guest memory by address, the
address build captures the program's code as an immutable snapshot, and
the two overlapped: the draw failed with "writable guest memory
overlaps an immutable snapshot", or, when the live bytes at the code
address had changed since the capture, "guest snapshot differs from the
writable memory it overlaps".

MeshIndexBufferDescriptor now returns a null V# (base and size 0, same
format word) for a non-indexed draw, which ShaderResources binds to its
empty placeholder buffer, and takes no unread address any more.

PPSA14632 (LEGO Horizon Adventures) hit this on its layered mesh-path
draws.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 15:18:10 +02:00
Adrià 8f510f31ab
Merge pull request #1066 from Celegans12/feat/shader-buffer-limit
feat(shader): accept more than 32 buffers per shader up to the device limit
2026-10-07 14:20:34 +02:00
Celegans12 0d38698dfe fix(agc): include PA_SU_POLY_OFFSET_CLAMP in the initial context state
A draw with depth bias enabled read PA_SU_POLY_OFFSET_CLAMP (context
register 0x2df) with read(), but the context bank only held it once
the title wrote it. Titles that rely on the reset value had every such
draw skipped with "missing register in context bank at DWORD 0x2df".

The initial context state, which CLEAR_STATE also restores, now holds
the register as 0. That is the value in libSceAgc's own register
defaults (sceAgcGetRegisterDefaults2, every version) and in amdgpu's
GFX10 clear-state table. A clamp of 0 means no clamping, so it needs
no device feature.
2026-10-07 11:46:11 +02:00
Adrià e2b527bb09
Merge pull request #295 from MichonGoddijn231849/split/pixel-ancillary
fix(shader): packed pixel ancillary as SampleId and Layer, gl_Layer via Geometry, Z export formats
2026-10-07 11:06:33 +02:00
alfalfa-star 1e28efbd26 feat(agc): accept 64-bit image atomics in graphics shaders
A pixel or vertex shader with a 64-bit image atomic declares Int64Atomics,
Int64ImageEXT and SPV_EXT_shader_image_int64, which graphics shader
validation rejected ("SPIR-V requires unsupported device capability"),
so the draw was dropped. Compute dispatches are not validated this way.

The device records whether it enabled shaderImageInt64Atomics
(imageInt64Atomics in the device state and the graphics Context), and
ValidateShaders accepts the two capabilities and the extension when it
did.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 10:35:24 +02:00
Michon 048d9982cd fix(agc): the Z-format precheck gives no verdict for a missing SPI_SHADER_Z_FORMAT
DrawRejection read 0x1c4 with read(), which throws when the register is
absent, against the function's rule that a missing register gives no
verdict there; it now reuses the value read with value() for the
DB_SHADER_CONTROL check. Tests pin the Z-export rules: formats 1, 2, 3
and 9 with Z_EXPORT_ENABLE accepted, format 0 rejected, the sample-mask
export accepted with 32_ABGR and rejected with 32_R, formats 4 to 8
rejected, and a missing 0x1c4 accepted.
2026-10-07 10:09:51 +02:00
Celegans12 1c5ed6594d feat(shader): accept more than 32 buffers per shader up to the device limit
The resource tracker refused a program's 33rd distinct V# with "buffer
resource limit exceeded". The 32 was a recompiler constant, not a
Vulkan limit: every buffer is one constant-indexed element of the guest
buffers binding, which ShaderResources checks against the device's
storage-buffer limits.

Drop ShaderInfo::MaxBuffers and the tracker's refusal, and size the
SPIR-V emitter's per-buffer offset list from the binding layout. When
the user data and offsets do not fit in the push constants, they all go
to the shader data buffer as before. ShaderResources counted only
storage buffers against maxPerStageResources (200 on Intel UHD) and now
adds the stage's sampled and storage images.

agc_driver_many_buffers reads and writes 52 and 124 buffers, and
agc_driver_graphics rejects buffers plus an image above the limit.
2026-10-07 09:17:47 +02:00
Celegans12 94cf99e361 feat(agc): implement 8 srgb color targets through rgba8 srgb proxies
CB_COLOR_INFO format 1 with number type 6 (8_SRGB) threw at decode.
It now decodes as R8_SRGB with component swap 0; the other swaps and
8_8_SRGB still throw.

A device that cannot attach and blend R8_SRGB (NVIDIA, lavapipe)
renders a resident 8_SRGB target through an RGBA8_SRGB view of an
RGBA8 copy of its R8 image: the image is blitted in before the pass
and back when the pass ends, and the write mask keeps R only, so the
encode, decode and blend are the device's sRGB attachment rules.
APS5_SRGB_ATTACHMENT_PROXY=1 forces the copy. Linear, mipmapped and
3D 8_SRGB targets throw on such a device.

PPSA26344 renders its G-buffer slot 5 and a multiply-blend pass into
8_SRGB targets.
2026-10-07 07:47:00 +02:00
Merijn ef10a36b8a fix(agc-driver): accept per-engine primitive discard in PA_SC_MODE_CNTL_1
Bit 17 of PA_SC_MODE_CNTL_1 (MULTI_SHADER_ENGINE_PRIM_DISCARD_ENABLE)
lets each shader engine drop primitives outside its screen region, a
work distribution setting with no visible effect. Draws with it set were
skipped as unsupported. PPSA12544 sets it (0x06020000, with the already
accepted EOV bits 25 and 26) on the draws that produce its presented
image, so every frame it presented was black.

AI-assisted: yes

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 10:42:03 +02:00
Dean 3bfa6e4fc4
Merge pull request #764 from Celegans12/feat/agc-dcc-a2r10g10b10-clear
feat(agc): encode the DCC clear codes of A2R10G10B10 color targets
2026-10-06 13:18:06 +13:00
Celegans12 4a67b140fc feat(agc): accept conservative Z export in DB_SHADER_CONTROL
DecodeState, the draw precheck and DecodePixelStageInfo rejected every
nonzero CONSERVATIVE_Z_EXPORT (DB_SHADER_CONTROL bits 13-14).
EXPORT_LESS_THAN_Z (1) and EXPORT_GREATER_THAN_Z (2) promise that the
exported Z stays on one side of the interpolated Z. The value now
reaches the recompiler as a pixel stage field, and a pixel shader that
writes FragDepth declares DepthLess or DepthGreater next to
DepthReplacing, the SPIR-V modes RADV maps to these values. Vulkan lets
those modes only add a depth test of the interpolated Z before shading,
so a shader that keeps the promise renders the same. The reserved value
3 still throws.

The field is part of the recompile cache key, the draw key and the
serialized request (version 7), and ValidateShaders accepts both modes.
2026-10-06 00:35:43 +02:00
Celegans12 3a48a57dc7 feat(agc): encode the DCC clear codes of A2R10G10B10 color targets
LayoutFor had no case for VK_FORMAT_A2R10G10B10_UNORM_PACK32, the format
of a COLOR_2_10_10_10 color target with the alternate component swap, so
FillDccClear could not encode its 0001, 1110 and 1111 clear codes. The
format now takes the A2B10G10R10 layout: the codes set the three color
channels alike, so both packings give the same words.

A draw into a copied target under these keys now starts from the clear
value instead of the stored texels, and clearTexel (the CB metadata pass
and storeClearTexels) returns the texel instead of throwing. Textures
and resident targets, stored as A2B10G10R10, and DccAlphaOnMsb are
unchanged. Split out of #648.
2026-10-05 23:45:16 +02:00
Celegans12 2eff3c8386 feat(agc): accept linear attribute clipping in PA_CL_CLIP_CNTL
DecodeState and the draw precheck rejected PA_CL_CLIP_CNTL bit 24
(DX_LINEAR_ATTR_CLIP_ENA), so every draw that sets it was skipped.
Vulkan requires clipped NoPerspective outputs to vary linearly in
framebuffer space, and RADV and radeonsi set this bit for every draw
they emit. With the bit set the console therefore clips the way the
host driver already does, and the pipeline needs no extra state.
Clip space, depth clamping and the viewport depth range decode as
with the bit clear. Every other unsupported bit still rejects the
draw, with or without bit 24.

TechnicalDebt records that a clear bit, which was already accepted,
gets the same clipping.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 17:50:57 +02:00
Dean 2cce4bde41
Merge pull request #469 from Pacuka/fix/agc-null-pixel-program
fix(agc): draw without a pixel program when SPI_SHADER_PGM_PS is unset
2026-10-05 21:36:35 +13:00
Dean Galvin 1c4aadb3e3 fix(agc): route compacted color exports to the slots CB_SHADER_MASK enables
Pixel shader color exports are compacted: export MRTi goes to the i-th
MRT slot with a non-zero CB_SHADER_MASK nibble and takes the i-th
SPI_SHADER_COL_FORMAT field. Draws still mapped export i to slot i and
read slot i's format field, so a shader with CB_SHADER_MASK 0xf000f and
SPI_SHADER_COL_FORMAT 0x44 (export 1 to slot 4) was refused with
"color export format 0".

Each color target now carries its export index next to its slot.
Attachment references, blend states, export mappings and the pipeline
and pass keys follow the export index; the color buffer, blend control
and target mask come from the slot. An unwritten export below the
highest written one stays an unused attachment.
2026-10-05 17:03:43 +13:00
Dean 4db07b3a77
Merge pull request #449 from MichonGoddijn231849/feat/3d-color-targets
feat(agc): render into one depth slice of a 3D color target
2026-10-05 11:45:29 +13:00
Dean 19f6e33f3e
Merge pull request #453 from SP4C3B4R-8/fix/absent-depth-stencil-plane
fix(libSceAgcDriver): skip depth and stencil tests whose plane is absent
2026-10-05 11:41:26 +13:00
Pacuka a48a9eabf7 fix(agc): keep the pixel register fallbacks to the null program and refuse its color writes
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-04 20:57:01 +02:00
Pacuka b90a913715 fix(agc): draw without a pixel program when SPI_SHADER_PGM_PS is unset
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-04 20:54:11 +02:00
Michon 34c57ca65d feat(agc): render into one depth slice of a 3D color target
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-04 12:24:09 +02:00
Michon d7d7c142f4 feat(agc): 4 KiB standard color targets and color views of one array slice
Color targets with the SW_4KB_S swizzle (CB_COLOR_ATTRIB3 tile mode 5) are laid out in 4 KiB
blocks with the standard element order the texture detiler uses, and are resident through the
same storage images as 64 KiB targets. A CB_COLOR_VIEW selecting one slice (SLICE_START equal to
SLICE_MAX) renders into that slice: the target starts one slice size per slice after the surface,
the slice size being the surface's mip chain as a texture of the same tile mode lays it out. Views
of several slices are still rejected.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-04 12:24:05 +02:00
SP4C3B4R-8 48ebf3195e fix(libSceAgcDriver): skip depth and stencil tests whose plane is absent
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-04 12:17:38 +02:00
Dean 0623b69325
Merge pull request #376 from MichonGoddijn231849/feat/depth-bounds-bias
feat(agc): depth bounds test and depth bias
2026-10-04 22:55:57 +13:00
Dean 33a2f907f4
Merge pull request #460 from oneandonlydean/perf/agc-gpu-mesh-indirect
perf(agc): draw mesh-stage indirect draws on the GPU
2026-10-04 16:15:58 +13:00
Dean 2cb95dab12
Merge pull request #452 from SP4C3B4R-8/fix/scissor-window-offset
fix(libSceAgcDriver): accept scissors that apply the zero window offset
2026-10-04 15:48:01 +13:00
Dean Galvin fb55cb2c0e perf(agc): draw mesh-stage indirect draws on the GPU
A mesh program took its draw's index count from push constants, so an
indirect mesh-path (NGG) draw needed the CPU to read its record first,
waiting for the GPU to finish everything recorded before. In PPSA21564
that was about 170 waits per 10 s at the title, menu and level (about
1 s), and one per frame in the intro (2.2 s per 10 s).

The two free mesh push dwords now carry the device address of an argument
record (a VkDrawMeshTasksIndirectCommandEXT followed by the index count
and first index). When the address is set, the prologue takes the index
count and the first index from the record (the new MeshArgument IR value,
a load through a physical storage buffer pointer) and offsets its index
reads by the first index; a direct draw leaves the address 0 and draws as
before. Mesh modules declare the physical storage buffer capability for
it, and the driver's SPIR-V validation accepts the extension in mesh
modules.

An indexed mesh draw with one record that patches no user SGPR now stays
on the GPU. A one-thread compute pass (Graphics/shaders/MeshArguments.comp)
turns the record, read in place from its host import, into the draw's
argument record: the groups and instances of vkCmdDrawMeshTasksIndirectEXT
and the index count and first index the mesh program reads, with the CPU
path's rules (count clamped to the index buffer, nothing for an empty
record or past the device's group limits). The index buffer descriptor
covers the whole buffer and the program offsets by the first index. When
the records cannot be read in place, the CPU reads them and fills the
same argument record (ResolveMeshArguments).
2026-10-04 15:45:56 +13:00
Dean 2ccd3d7b56
Merge pull request #440 from oneandonlydean/feat/agc-fan-gs-input
feat(agc): take triangle fans as NGG geometry shader input
2026-10-04 15:44:54 +13:00
Dean 53d1ebc10f
Merge pull request #459 from oneandonlydean/perf/agc-own-stack-verify
perf(agc): answer verifications of the caller's own live stack without a page query
2026-10-04 11:34:24 +13:00
Dean d8e2609831
Merge pull request #442 from oneandonlydean/fix/agc-host-page-query-gap
fix(agc): describe the pages after a gap in a Linux host page query
2026-10-04 11:32:41 +13:00
Dean Galvin 5a8165282f perf(agc): answer verifications of the caller's own live stack without a page query
Driver::Submit checks the title's submission packet, which the title
passes on its own thread stack. Host thread stacks are neither registry
mappings nor write-watched, so no page-state cache covers them and on
Linux every check scans /proc/self/maps line by line: about 1.5 ms per
submission on the render thread of PPSA21564 (66% of that thread's
samples in perf at the title).

A range between the calling thread's current frame and its stack's top
holds the frames of every caller, so it is mapped readable and writable
for as long as the call lasts; verify() now accepts it without a query.
A thread on another stack (a fiber's, a signal stack) has its frame
outside the thread's bounds and still gets the page query, as does any
range that runs past the stack's top or starts below the frame.

GetCurrentThreadStackLimits needs _WIN32_WINNT 0x0602 on MinGW, as
libkernel already sets; GuestMemory.cpp is compiled by several targets,
so the definition is a property of the source file.
2026-10-04 03:02:25 +13:00
SP4C3B4R-8 579db05081 fix(libSceAgcDriver): accept scissors that apply the zero window offset
PA_SC_WINDOW_OFFSET is already required to be zero, so a generic,
window or viewport scissor whose WINDOW_OFFSET_DISABLE bit is clear
selects the same rectangle as one that sets it. Only the reserved
bits are still rejected.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018m6Ad8zkQKPKZmyUQK9vfE
2026-10-03 13:15:28 +02:00
Michon 057bcb1b42 fix(agc): refuse depth bounds outside [0, 1] without VK_EXT_depth_range_unrestricted
Clamping them changed the result where the stored depth is exactly 0 or 1.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-03 10:40:47 +02:00
Michon c15238ddc0 feat(agc): depth bounds test and depth bias
DB_DEPTH_CONTROL's DEPTH_BOUNDS_ENABLE now runs the Vulkan depth bounds
test with DB_DEPTH_BOUNDS_MIN/MAX, and PA_SU_SC_MODE_CNTL's
POLY_OFFSET_FRONT/BACK_ENABLE enable depth bias from
PA_SU_POLY_OFFSET_FRONT/BACK_SCALE/OFFSET and _CLAMP. Both are dynamic
state, so draws that differ only in their values share a pipeline.

The hardware slope scale is in 1/16 units. Depth bias with units other
than the depth format's (PA_SU_POLY_OFFSET_DB_FMT_CNTL), or that differs
between front and back faces that are both drawn, is refused. The
registers join the draw key. Depth-conditional color writes are still
refused.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-03 10:40:47 +02:00
Dean Galvin a18cf0fc32 fix(agc): describe the pages after a gap in a Linux host page query
Without VirtualQuery, a range no cached page table covers is looked up
line by line in /proc/self/maps. A cursor in a gap between mappings never
matched a line, so the scan parsed the whole file and then reported the
rest of the range unmapped, including mapped pages after the gap. The
scan now stops at the first mapping above the cursor, reports the gap up
to it as inaccessible and continues from there, as the VirtualQuery path
does with a free region.

PPSA21564 queries near-null addresses (0x18, 0x30, 0x58) about 1500 times
a second during resource capture; each of those parsed the whole maps
file (about 5700 lines here) instead of stopping at the first mapping.

Tests: agc_driver_graphics_tests describes three host pages with the
middle one unmapped as two ranges, a query that starts in the gap as the
page after it, and a near-null address as inaccessible.
2026-10-03 20:16:30 +13:00