APS5_SPANNED_WAVE is now read once by the driver, which sets
SpirvTarget::spannedWaves only on a device with 32-lane compute subgroup
control and computeFullSubgroups. The recompiler no longer reads the
environment. The field is part of the cache key and of the request
serialization (version 32), so a cached or replayed module keeps the mode
it was built in.
A spanned module numbers its lanes SubgroupId * 32 +
SubgroupLocalInvocationId, which needs two full 32-lane subgroups. The
artifact records this as fullSubgroups (disk cache and pipeline identity
included), and the driver creates those pipelines with
REQUIRE_FULL_SUBGROUPS. Compute pipeline captures accept the flag with a
required subgroup size.
The two-lane fallback now catches only SpannedWaveUnsupported, thrown for
a shuffle wider than 32 bits; other emit errors surface as before.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A graphics pipeline the store builds or a compute pipeline a dispatch builds is
appended to pipelines.journal next to the shader cache entries, as the
materialized result of each stage (the specialized SPIR-V, bindings and push
constants) plus the recipe the pipeline was built from: the stages'
identities, vertex input layout, descriptor set layout keys and the state
fields the Pipeline constructor reads. When a VulkanDevice is created with a
window (a headless device waits for its first draw or dispatch, since the
window's device usually replaces it first) the journal is loaded and its
pipelines are built on a pool of threads while the title loads, so the first
draw or dispatch of a configuration seen on an earlier run finds its pipeline
resident instead of compiling it on the queue worker.
The pipeline stores key on RecompileResult::Identity, a hash of the module
words, specialization constants, subgroup width and bindings that is the same
on every run (SharedSpirv::ContentHash, computed once per shared module),
rather than on the process-lifetime variant ids; a generated stage is keyed
like any other. CachedPipeline builds outside the store's mutex and the
library parts and link are built outside the library store's mutex, so replay
threads and queue workers build in parallel; a concurrent build of the same
key keeps the first inserted. A replayed pipeline enters the store at its
least recently used end and a full store takes none, and its optimized relink
waits for the first draw that binds it, so the title's own pipelines come
first in both. The compute pipeline creation moves into
VulkanDevice::createComputePipeline, shared by dispatches and the replay. The
store key also covers the color component mapping, the depth target's sample
count and a depth bias clamp, which the constructor reads.
The file names the device it was written for (the properties the driver's
pipeline cache file is named by) and starts over for another; a torn tail is
cut at a record boundary; two runs sharing the directory take turns on a lock
file and keep each other's records; a read failure never starts the file
over. A device cancels its replay before it is replaced or destroyed, and a
replaced device destroys its pipelines then rather than at the driver's stop.
APS5_NO_PIPELINE_JOURNAL=1 disables it; APS5_PIPELINE_JOURNAL_THREADS,
APS5_PIPELINE_JOURNAL_ENTRIES (the first recorded), APS5_PIPELINE_STORE_ENTRIES
and APS5_PIPELINE_JOURNAL_MAX_MIB bound it; APS5_PROFILE_DRAW prints a
[pipeline-journal] summary. APS5_VERIFY_SET_LAYOUTS=1 now also checks a
dispatch's set layout against the one described from its shader. The lavapipe
test suite, which shares one cache directory, runs with the journal off except
for the journal's own tests.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P6hw3kRAuQdfcU9YCZgaoK
The per-draw capture of a shader's memory (the SRT walk and the guest pages it reads) cost about
15 us per draw packet in GTA V Performance mode; it now costs about 6.6.
- The SRT evaluator memoizes per plan value in a thread's reused, stamped array instead of a hash
table allocated and grown on every walk (evaluate 5.3 -> 3.6 us per capture).
- ExtractPlan also stores the plan's values as 32-byte records with argument ids, and the walk
evaluates that compact copy: the IR walk spent most of its time in cache misses (3.6 -> 2.7 us).
The evaluator is a template over the node view, so both walks share every opcode's semantics, memo,
cycle and failure rules. A plan that cannot be expressed compactly keeps the IR walk.
APS5_VERIFY_SRT_COMPACT=1 walks both and throws on any difference.
- ShaderMemory's valid/read/recent marks are arrays of 64-bit words scanned with countr_zero instead
of bitsets tested bit by bit (about 1 us per draw packet).
- Captured pages come from a per-thread pool, are found through a short vector with a last-page
shortcut, and a page no recorded GPU work writes gets the flush hook a whole-page read would make,
then has each 64-byte block copied when a word of it is first read (about 0.3 us per packet).
Pages with pending GPU writes and unmapped pages are read as before.
- APS5_PROFILE_DRAW splits the capture time into SRT evaluation and materialization, and prints the
[capture] line once per 10 s instead of every 500 captures (it cost about 2 us per capture).
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Gjon Gojcevic <7807870+gjonn@users.noreply.github.com>
With fragmentShaderBarycentric (RADV, NVIDIA), v_interp_p1_f32 and
v_interp_p2_f32 are translated as P0 + I * P10 + J * P20 over the
per-vertex values, so every smooth input became per-vertex. A triangle
strip drawn with PROVOKING_VTX_LAST then threw "last provoking vertex
with explicit per-vertex triangle-strip interpolation is unsupported"
for any shader that interpolates, which stops OliSe Player (PPSA01153)
and RetroArch's ES-DE frontend (PPSA99169), both ps5-opengl titles
whose shaders use only v_interp_p1/p2.
I and J come from gl_BaryCoordKHR[1] and [2], in the same vertex order
as the pervertexEXT values, so the result is b0 * v0 + b1 * v1 + b2 * v2
whatever order the device gives an odd strip triangle. Only a shader
that reads a slot itself depends on that order. The translator now
records the inputs read through v_interp_mov_f32 or 16-bit
interpolation, FragmentParameter carries that as vertexOrder, and the
strip check refuses those alone. 16-bit interpolation would cancel out
the same way but has not been checked, so it stays refused.
ds_add_f32 and ds_add_rtn_f32 now follow the measured hardware: both
operands are flushed to a signed zero when bit 0 of the f32 denormal field
is clear and the result when bit 1 is clear, the sum is rounded to nearest
even, a NaN data operand is stored quieted, else a NaN old value is stored
quieted, and +inf + -inf stores 0xffc00000. Measured on gfx1010 and, in
#5492, on gfx1031.
The new MemoryInfo field is stored in the shader disk cache (field count
31, minimum record 79 bytes, FormatVersion 34). The parts that depend only
on the data operand are computed once, before the CAS loop.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Advance the stencil artifact schema past current main format 31 and retain explicit rejection of that format. Update Linux artifact size guards for main runtime image resource metadata.
Co-Authored-By: Codex <noreply@openai.com>
Preserve instance and triangle order with one dynamic-reference shader pipeline. Require bounded references, complete export coverage, replay-safe mask control and resources; refuse unsupported side effects and feedback.
Co-Authored-By: Codex <noreply@openai.com>
Read-only packs of encoded cache entries are mapped once at startup from
the shader cache prebuilt directory (plus ANYPS5_PREBUILT_SHADER_CACHE,
opt out with ANYPS5_NO_PREBUILT_SHADERS). Disk loads try packs and loose
prebuilt folders first and fall through to the writable cache and the
compiler on a miss. Keys, source version, format and payload checksums
are validated exactly as for writable entries, and interval logs report
prebuilt hits, misses, rejections and load timings.
Depends on the uncached compile entry point only through the offline
tool that produces these packs; the loader itself is independent.
Raise the pinned ImageResource field count and the minimum image record
size for the new field, and move the disk format to 34.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
A 3D image access bound to a 1D T# matched no runtime image mode and threw
"image descriptor is incompatible with the static runtime image interface"
(SONIC SUPERSTARS, PPSA06888, which reads a 1x1 1D T# as 3D with a plain
image_sample and an image_load). Add a 1D mode for 3D accesses whose only
uses are image_sample_lz, plain image_sample or mip-less image_load.
Measured on RDNA1 (RX 5700 XT, gfx1010) with the hardware oracle:
image_sample_lz reads the texel u selects and ignores v and r with every
addressing mode; a plain image_sample takes its texel and LOD from u alone;
image_load reads the x texel for any y when z is 0 and returns zero for any
other z, as the 3D-on-2D load measured in #2023 does.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QQNVXyqeecpyneonkYL6H1
A descriptor whose dwords come from two scalar buffer loads of the same
record, where one load's offset carries an immediate addend, was refused
because the column wanted one offset expression and one buffer node for
every dword. The column now peels an immediate addend off each read's
offset and compares effective offsets (memory offset plus addend) and
the remaining base expressions, and accepts distinct buffer nodes that
are equivalent. Dword 0 keeps its offset expression, so columns that were
already planned are planned the same way.
Folding a second load into the first changes where its offset wraps:
at a dynamic offset of 0xfffffff0, a second load at +16 wraps to the
start of the buffer, while the folded read lands past 4 GiB. A column
folds a load only when its addend is no smaller than dword 0's and its
immediate is small, and it records dword 0's addend and the largest extra
addend. A record whose offset would carry past 32 bits between the two
loads is not read and becomes OffsetCarry poison.
PPSA26344 pixel shader 0x8000296000 reads T# dwords 0-3 with an
s_buffer_load_dwordx16 at key * 0x88 and dwords 4-7 with an
s_buffer_load_dwordx4 at 48 + key * 0x88.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A table column can now read its descriptor through a 64-bit pointer
stored in each record: the shader loads the record's pointer at
key * stride + addend + offset from a scalar buffer, then the T# (or S#)
through that pointer. The materializer reads each record's pointer when
it builds the table, reads the descriptor behind it and records one
read range per record. Pointer columns take their own path ahead of the
batched record reader, since a descriptor's address is known only once
its record's pointer is read. The column is planned only when the descriptor
dwords are read at an immediate offset from a GetAddressResource whose
two dwords are consecutive reads of one buffer at the same affine offset.
PPSA26344 compute shader 0x8000333c00 picks a record per lane in a
waterfall loop, reads the record's pointer from it and samples the
image behind it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Plan runtime-indexed T# and S# columns read through a 64-bit pointer.
Preserve the console offset alignment, signed immediate and key bounds.
Track the descriptor dwords consumed by each table in its invocation.
Reject table reads when a writable buffer or storage image overlaps them.
Cover the overlapping-storage fault and isolated second-table behavior.
Materialize runtime-indexed image and sampler records into descriptor
tables while keeping descriptor selection in the shader. Report invalid
active entries through the existing deferred fault buffer.
Bind fragment tables in the fragment set when pipeline libraries split it,
and reserve a physical descriptor for empty tables. Reject unsupported
sampler, border, cube and anisotropic pairings per entry. Keep one column
per heap access shape, one T# shared by several image operations included
(milescoviello's #5550 case), and narrow it to the union of its keys'
domains when every key has one (SleglJan's key-domain changes). Plan
columns read at (key << n) & mask over their whole domain (tibzejoker's
fix). Read records in runs through SleglJan's bulk reader, and reject
entries whose surface has no mapped byte, as Tamalero proposed. Store
table columns in disk plans; update the runtime ABI and disk format. Bound
table-sized entries in the resource cache (65,536 table elements) and the
dispatch cache (256 MiB of captured words), evicting LRU.
agc_driver_waterfall_images fails on main since fd438f663: its compute shader
runs an LOD query with a local size of 8x1, and the module gets
DerivativeGroupQuadsKHR, which SPIR-V validation rejects unless both
dimensions are even (VUID-StandaloneSpirv-DerivativeGroupQuadsKHR-10151).
This reverts commit fd438f663, reversing changes made to 51031742e.
Co-Authored-By: Claude <noreply@anthropic.com>
The disk resource plan codec added on main must retain whether an indirect
image uses a per-lane key, an indexed record stride, and implicit derivatives.
Encode and decode those fields, update the aggregate field guard, and reject
the older resource-plan format. Cover all eight flag combinations so a loaded
plan cannot silently lose the stride or bound-mode checks.
Co-Authored-By: Codex <noreply@openai.com>
ShaderCacheVersion.cmake wrote the source version and the APS5_* switch
list into a generated ShaderCacheVersion.hpp that ShaderDiskCache.cpp
included. The version hashes every recompiler source, so any content
change under core/shader/recompiler rewrote that header and recompiled
ShaderDiskCache.cpp next to the file actually edited.
The script now writes ShaderCacheVersion.cpp, which defines
Generated::SourceVersion and Generated::RecompilerSwitches (a span over
the same sorted switch list) with constinit. They are declared in the
new ShaderCacheSourceVersion.hpp in the source tree, which
ShaderDiskCache.cpp includes; the generated directory is no longer an
include directory. The header has a different name from the old
generated one so that a build directory that still holds the stale
ShaderCacheVersion.hpp next to the generated .cpp cannot pick it up.
What is hashed is unchanged: the same manifest (recompiler sources,
HostThreadLocal.hpp, submodule commits, compiler, build type,
architecture and flags), the same checks and the same rewrite-only-
when-different step, so the version still changes exactly when it did.
Running the upstream/main script and this one with the same arguments
over this tree gives the same version (0x7907101dc4d8c62e) and the same
26 switches, and a second ninja run has no work to do. The value
differs from the one main 682ef0c17 generates (0xdce3a0ce03bf030a) only
because this commit edits hashed files, as any recompiler change does.
Tested with ninja -d explain -j 4 shader_recompiler_agc_driver,
CCACHE_DISABLE=1, after appending a line to
IntermediateRepresentation/src/IrType.cpp, three runs on main and then
three runs on this commit back to back, with the machine at 100% CPU
from other builds. On main ShaderCacheVersion.hpp and
ShaderDiskCache.cpp.obj are dirty and the rebuild takes 22.0/23.9/22.2 s.
With this change only ShaderCacheVersion.cpp.obj and IrType.cpp.obj are
compiled, ShaderDiskCache.cpp is absent from the explain output, and the
rebuild takes 12.2/14.7/15.0 s. The shader and recompiler ctest set
(26 tests) passes.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Codex <noreply@openai.com>
A cached variant kept its SPIR-V in memory for the whole run. On Linux and
macOS the words are now a view into the mapped cache file, and a freshly
compiled variant is written and mapped back, so the kernel can drop them.
PrepareRegistered prepares every registered pixel shader twice: with the
plan's layout, then with pushConstantSizeBytes = 0. The layout is not part
of the source key, so both requests share one SourceEntry, but the first
variant consumes the entry's front-end program. On a cold cache the second
layout therefore ran PrepareResourceProgram again (translation, SSA, the
fold and eliminator passes, SrtWalker, ResourceTracker) and the interface
passes after it, although none of them reads the layout. Only decode, CFG
and structurization were shared through the context (#2526).
A ShaderPreparationContext now keeps the program it last emitted from,
after the interface step, together with its source entry. Another layout of
the same source at the same code address resets the binding allocation and
emits from that program, as the registration word-limit fallback already
does within one variant, and copies the compiled information out instead of
moving it. A different source or code address builds a program as before.
Building another program through the context releases the kept one first,
and the program dies with the context, so no program outlives the
registration that built it (the rule of #471). ResourcePrograms() counts
the programs built through a context.
Disk-cache loads and stores, the emission-failure memo and the variant
order are unchanged. APS5_NO_PERF_LAYOUT_PAIR=1 restores the previous path;
it is a neutral switch, so it does not change disk-cache keys.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The plan and ShaderInfo encoders write these structures field by field,
and the sizeof asserts are their only reminder to update the encoders. A
field that fits in existing padding keeps the size: main's layerExported
landed in ShaderInfo with sizeof still 232, and the three bools #5089
adds to DescriptorSource::IndirectImage keep it at 28. A warm cache
would then hand back entries without the new field and nothing would
fail.
Count the fields of every aggregate the plan codec reaches (IrResourcePlan,
GuestRegister, MemoryInfo, DescriptorSource and IndirectImage,
ResourceBlock, SrtRead, UniformFill, UniformFillPlan, and ShaderInfo with
its resource and stage I/O records) by brace-initializing each with more
and more convertible-to-anything values until the initializer no longer
compiles, and assert the counts. Unlike the size asserts this does not
depend on the ABI, so it is checked on every platform. IrValue is a
class with private state and keeps only its size assert.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
DecodePlan checked every descriptor source index a plan holds except the
two inside an indirect image table: the heap source and the material
source. A damaged entry could therefore decode with a table that points
past the plan's descriptor sources, and only the materializer's own
bounds checks stood between it and an out-of-range read. The front end
interns both sources before the image source that names them, so a plan
it builds always passes the new check.
agc_shader_disk_cache now requires a plan whose table heap or material
source lies past the sources not to decode.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
getSource built ResourceProgram (PrepareResourceProgram and ExtractPlan)
for the first request of every shader a process saw, before
findOrCompileVariant looked in the disk cache. With a warm cache every
launch still decoded, built the CFG, structurized, translated and ran
SSA, the fold passes, SrtWalker and ResourceTracker for every shader;
only SPIR-V emission was skipped.
getSource now builds the plan key and tries LoadPlan first. On a hit it
sets the plan and leaves the program null: findOrCompileVariant already
rebuilds the program when no stored variant fits the layout. The loaded
plan takes the request's code address as its shader hash, as a plan
built in this process would. On a miss it builds the plan as before and
stores it. A plan the front end refuses is not stored. The disk is not
used when the cache is off, under the debug probe, with APS5_DUMP_IR
(which prints the front-end passes), or with APS5_NO_PERF_DISK_PLANS=1,
a cache-neutral switch for comparisons.
FrontEndBuilds() counts PrepareResourceProgram calls. The new
cross-process test prepares, captures and materializes 14 shader
fixtures in one process and repeats it in a second process sharing the
cache directory: the second process must run the front end 0 times, hit
14 plans and 14 variants, and produce byte-identical SPIR-V, bindings,
push constants, snapshots, read traces and plans. A damaged plan entry
is rejected and rebuilt alone with the same output and stored again; a
changed code word and another switch value miss.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The disk cache keeps compiled variants (SPIR-V, shader info, binding
layout) but not the IrResourcePlan the front end extracts for the
resource walk, so a process can only get a plan by running the whole
front end. Since #471 the plan owns its values (ownPlanValues clones the
graph behind every root into valueStorage and blockStorage), so it can
be written out and rebuilt.
- EncodePlan writes the value graph in storage order, each value as
LEB128 integers: opcode, type, id, flags, register, operand count,
the immediate if it has one, each argument as the zigzag distance to
the value's own index (0 for null) and, for phis, the index of each
predecessor block. The roots (descriptor source dwords, SRT reads,
control-flow conditions, uniform-fill values) are value indices; the
plain data (memory info, indirect image tables, control-flow edges,
materialization sources, guarded, clean and pure flat slots, the
flags, the ShaderInfo through the variant's encoder) follows. A plan
whose roots or arguments point outside its storage is not encoded.
Control-flow conditions can pull most of a program into the plan:
a synthetic 2,038-dword compute shader with a branch every 20 dwords
has 42,775 plan values, which take 518 KB this way and 2.5 MB with
fixed-width fields; its compiled variant entry is 935 KB.
- DecodePlan rebuilds the graph the way ownPlanValues does and rejects
an unknown opcode, an overlong integer, an index past the values or
blocks, a descriptor source, image, buffer or sampler past the
sources, a branch without two successors, an edge past the blocks,
and a uniform fill of more than four words.
- BuildPlanKey is the in-memory source key (RecompileCacheKey::Build and
the host subgroup size), every code word and the switch key, after a
plan entry tag. It leaves out the binding layout, so all layouts of a
shader share one plan.
- EncodePlanEntry/DecodePlanEntry use the variant's header and hashes;
LoadPlan and StorePlan use the same directory and background writer
and count plan hits, misses, writes and load failures on their own.
- Size asserts cover the plan and the structures it is written from.
- FormatVersion 30.
agc_shader_disk_cache now round-trips the plans of 14 in-tree shader
fixtures (SRT reads, guarded and chained pointers, control-flow
conditions, an indirect image table, a loop phi, a fragment shader) and
a hand-built plan with a uniform fill. For each it materializes the
original and the decoded plan over 1000 random user-data and memory
runtimes and requires the same snapshot, poison, null-root count and
read trace, or the same error. Truncated, bit-flipped and
other-format entries are rejected, malformed plans do not decode, and
the key follows the code, the target and the host subgroup size but not
the layout, addresses or user data.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
encodeInfo and decodeInfo wrote the ShaderInfo fields inline between the
compiled-shader header and the binding layout, and EncodeEntry and
DecodeEntry built and checked the file header (magic, format, source
version, key and payload hashes) inline. Move both into helpers,
encodeShaderInfo/decodeShaderInfo and wrapEntry/unwrapEntry, so that a
second kind of entry can reuse them.
The bytes of a compiled variant entry do not change.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A packed ancillary word that still reaches an export, or any other read
the masked-select pass cannot drop, no longer stops the recompile. After
that pass every remaining use gets the composed word: the primitive class
at bits 0-1, SampleId at bits 8-11 and Layer at bits 16-28, with every
other bit zero. Those lanes do export the ancillary VGPR on the console,
so the word has to be right, not just present.
The primitive class (0 point, 1 line, 2 triangle, 3 rectangle) comes from
the draw. RasterPrimitiveOf maps rect lists to 3, line lists on the vertex
path to 1 and everything else the driver accepts to 2, because its
geometry and tessellation paths only output triangles. It reaches the
shader as pipeline specialization constant 8233, the way dual-source
blending does: a request field that is folded into the specialized
module and is part of the result memo, the draw key and the serialized
request (version 17).
Only shaders that read the class pay for it. ShaderInfo records the read
(disk cache format 28), and only those shaders put the class in their
module key, so a shader that reads just the sample or layer field keeps
one module for every primitive class. The draw sets the class only when
the pixel shader loads the ancillary VGPR, so other draws keep the draw
cache entries they have today.
The VRS rates (bits 2-5) and the eye id (bit 7) are 0 because the driver
supports neither VRS nor multiview. SampleId is 0 because the driver
rejects MSAA and per-sample shading, and Layer is 0 while it ignores
vertex layer exports. TechnicalDebt.md records the layout sources and
these assumptions.
Tests:
- pixel_ancillary builds an export to target 0 whose two channels select
between a packed value and a phi carrying the word. It checks the word
for each primitive class, sample and layer, checks that the three
shapes the masked-select pass keeps now compile with the composed word,
and that a program whose select the pass drops reads no class.
- agc_driver_pixel_ancillary_word exports the word from a draw and reads
back 2, 3 and 1 for triangle, rectangle and line. A shader that reads
only the sample field shares one module across the classes, and the
whole-word shader gets one per class. It also checks RasterPrimitiveOf.
- agc_shader_memory covers the version 17 round trip, and
agc_shader_disk_cache the new flag.
Both ancillary tests fail with the old refusal when the composition is
disabled.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ShaderCacheDirectory located the executable through /proc/self/exe,
which macOS does not have, so it returned an empty path there and
the shader and pipeline disk caches were silently disabled unless
ANYPS5_SHADER_CACHE_DIR was set. Use _NSGetExecutablePath and
resolve the path with std::filesystem::canonical on macOS. Linux
and Windows are unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A FLAT_SHADE input without pass-through that a pixel shader reads
through v_interp_mov_f32 P10 became an explicit per-vertex input and
read vertex 1 minus vertex 0. With the last provoking vertex the
pipeline then threw ("last provoking vertex with explicit per-vertex
flat interpolation is unsupported"), which stopped all three
ps5-opengl titles in the catalog.
ps5-opengl reads every flat input through P10 when GL's last-vertex
convention is in effect, and its driver passes the GL 4.6 CTS on a PS5
(#1413). Such a read now returns the provoking vertex's value, as P0
does, and only a P20 read keeps a flat input per vertex. The lane was
not measured on the console itself, so FragmentParameter records it
and a pipeline using the first provoking vertex throws.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>