Image and sampler table capacity came only from the regular descriptor
limits. MoltenVK reports Metal's argument table limits there (256 sampled
images and 16 samplers per stage), below the typed heaps the tables are
reserved on top of, so both capacities were 0 and every table draw or
dispatch was refused as if the device lacked descriptor indexing. Its
update-after-bind limits are 1000000 sampled images and 500000 samplers.
- descriptorBindingSampledImageUpdateAfterBind is queried and enabled, and
the update-after-bind limits are read when either it or the storage
buffer feature is present.
- A table whose regular capacity is 0 takes its capacity from the
update-after-bind limits. Its binding is update-after-bind and its set
layout and pool are update-after-bind ones, in ShaderResources and in
DescribeSetLayouts alike. A table that fits the regular limits is
unchanged.
- An update-after-bind set layout and its allocation are checked against
the update-after-bind sampled image and sampler limits when the device
has descriptorBindingSampledImageUpdateAfterBind. Vulkan counts the
descriptors of such sets against those limits in place of the regular
ones, and requires them to be at least the regular ones only when the
feature is supported, so without it, and for storage images, the
regular limits are kept as before. Storage buffers keep their own
update-after-bind flag.
- Compute pipeline capture and replay accept update-after-bind sampled
image and sampler bindings.
Filled rectangles (VGT_PRIMITIVE_TYPE 7 and 17) use the same single-sample MSAA_ENABLE path as triangles; PPSA03541 stops on a rect-list draw otherwise.
Co-authored-by: Cursor <cursoragent@cursor.com>
Use representable viewport endpoints only when the draw has no depth attachment and its pixel shader does not read PositionZ. Preserve XY coverage, clip-space mode, depth clamping, and validation of non-finite inputs.
Balatro (PPSA21402) reaches rendering on Apple M1 with MoltenVK after this change instead of stopping at VK_EXT_depth_range_unrestricted. Depth-dependent draws retain their original behavior.
Primitive type 19 (DI_PT_QUADLIST, 0x13) is used by Unity and other engines for UI quads, sprites and font glyphs. Because Vulkan lacks native quad-list primitive topology, quad draws are expanded on the CPU into indexed triangle lists with 6 indices per 4-vertex quad, respecting the first/last provoking vertex configuration and discarding incomplete trailing vertices. Adds unit tests and documents the functional debt.
A draw on the mesh path was validated before its pipeline checked for
mesh shader support, so on a device without VK_EXT_mesh_shader (an RDNA1
RX 5700 XT) Sackboy: A Big Adventure (PPSA01289) stopped on "subgroup
capability 61 is unsupported for shader stage 128" instead of the actual
cause. ValidateShaders now takes the device's mesh shader support and
refuses such a draw first with "device does not support mesh shaders".
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
PPSA08270 (Eternights) stopped after its story intro with "AGC graphics:
CB resolve from a target whose sample count differs from the
rasterizer's". It resolves a 4x 512x512 target into a single-sample one
with PA_SC_MODE_CNTL_0.MSAA_ENABLE off while PA_SC_AA_CONFIG still holds
2x from earlier draws. Without MSAA_ENABLE the scan converter does not
use PA_SC_AA_CONFIG's sample count, so the resolve takes its sample
count from CB0 as it already does when PA_SC_AA_CONFIG is single-sample.
DescriptorCache::AllocateRewritten handed out any recycled set of the requested layout. The
variable descriptor count of an image-table binding is fixed when its set is allocated, and
PrepareDrawBindings writes the table's present elements, up to its current element count, into
the set it gets. A draw whose table had more elements than the table the recycled set was
allocated for could write descriptors past the set's allocation
(VUID-VkWriteDescriptorSet-dstArrayElement-00321).
A set from a chain pool now records the variable count it was allocated with, as a dedicated-pool
set already does, and recycled sets are kept per layout and variable count, so a rewritten draw
reuses a set only for a table of the same size.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Imports, type-3 mirrors and the buffers and textures placed in host memory share the driver's system memory heap. On Windows that heap is half the physical memory, so on a 16 GiB machine the old budget (the heap less 2 GiB) let imports hold about 6 of its 8 GiB, and host buffer allocations then overflowed into the 256 MiB device-local host-visible heap and failed. The budget now reserves the larger of 2 GiB and half the largest host heap.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Since #6196, a one-sample target under a multisampled rasterizer with
MSAA_ENABLE clear is drawn as one sample instead of refused, so the
overrasterized draw with MSAA_ENABLE clear now decodes as one sample without
merged coverage.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Pipeline creation and the pipeline store key read State::mergedCoverage,
but the journal's state codec and CanonicalPipelineState dropped it, so a
journalled merged-coverage pipeline replayed as a plain multisampled one
and the draw built its pipeline again. The codec and the canonical state
now carry it and the journal format becomes 4.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A radeonsi-style GL driver smooths lines and polygons by rasterizing four
samples into a one-sample color target: PA_SC_AA_CONFIG has 4 samples,
DB_EQAA.OVERRASTERIZATION_AMOUNT is log2(4), and the pixel shader reads
SAMPLE_COVERAGE to scale alpha by the covered samples. The pixel is written when
any of the four samples is covered. DecodeState refused the one-sample target as
a sample-count mismatch.
Such a draw (MSAA_ENABLE set, no depth target, no per-sample shading, every
color target one-sample, OVERRASTERIZATION_AMOUNT matching the raster samples)
now decodes with mergedCoverage. Its pipeline keeps the raster sample count,
gives the color attachments one sample (VkAttachmentSampleCountInfoNV or the
render pass) and merges coverage (VK_COVERAGE_REDUCTION_MODE_MERGE_NV). The
device enables VK_NV_framebuffer_mixed_samples and VK_NV_coverage_reduction_mode
when it reports that combination; elsewhere the pipeline throws.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The custom MSAA sample-location debt entry keeps this branch's grid stand-in text and takes main's sentence on ANCILLARY and the position inputs of a once-per-pixel shader.
SPI_PS_INPUT_ENA/ADDR bit 14 (SAMPLE_COVERAGE_ENA) gives the pixel shader one
VGPR, after ANCILLARY, holding the samples the primitive covers. The decoder
refused it and the recompiler never loaded the VGPR. It is now loaded from
gl_SampleMaskIn[0] (sharing the input the partial quad sample mask already
declares). On a multisampled draw the hardware word is the whole pixel's
coverage while gl_SampleMaskIn holds only the invocation's samples when the
pixel shader runs per sample, so that case, and sample-rate or ancillary inputs
beside it, are refused.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The data-hit verification keeps this branch's pending-span query on its ShaderMemory and takes #5958's CaptureInvocation, which retries a capture with converted samples.
Keeps this branch's tagVariantRuns declaration next to main's dumpRequest suffix parameter in Driver.hpp, and reads #6232's pointer-chain test words from its table's snapshot, where this branch keeps them.
Charge read-only GPU-copy input snapshots and depth-copy linear scratch for their requested bytes while the batch retains them. Exercise both production paths with CPU Vulkan mocks, including the budget boundary and fence-governed resource retention.
Co-Authored-By: Codex <noreply@openai.com>
Resolves the shader debt file bullet by bullet: main's EmitSetAttribute entry, and this branch's PERSP_SAMPLE/LINEAR_SAMPLE and pixel-position entries.
#7527's selected-record limit test reads a record's descriptor words through the
table snapshot's shared words list; this branch keeps a snapshot's words per column,
so the test reads them from its column instead.