Retain the regression originally supplied by Pipodi in closed PR5851 (22091410a), adapted here through e1c6af65b. Current-main-equivalent libc/kernel source returns an alias during the open HostWrite and fails this assertion five times. This test is a reproduction, not a new implementation or an upstream PR.
(cherry picked from commit 312170cd0c461104174d655911de876be341cf6a)
Retain Pipodi safety guard from closed PR5851 without its resident alias expansion or automatic AGC alias routing. Main still refuses aliases over partial resident runs. Five unmodified-main regression runs fail before this guard; positive validation pending. Fork proposal only; no duplicate upstream PR intended.
(cherry picked from commit 078a5740b40c3b5b6384eec8f92363360c75b758)
A draw whose sample locations vary between the pixels of the guest's
2x2 pattern threw "sample locations varying between pixels require a
2x2 sample location grid for the draw's sample count" on a device
whose maxSampleLocationGridSize for that sample count is not a
multiple of 2x2. An RTX 3070 Laptop GPU reports 1x1 for every count,
so Resident Evil Village's 2x checkerboard pattern stopped there
before its title.
The pipeline now decides the grid when it is created: such a pattern
is drawn through a 1x1 grid with pixel (0,0)'s locations, the first
registers of the pattern and the pixel the guest's grid is anchored
at, and the first such pipeline of each sample count logs it. The
render pass begin takes the pipeline's grid, so a sample-location-
compatible depth image is begun with the locations it is drawn with.
Devices with the grid keep it, and uniform patterns are unchanged.
On macOS the RLIMIT_NOFILE soft limit is not a bound on the descriptor table: setrlimit accepts soft limits above kern.maxfilesperproc, RLIM_INFINITY included, and getrlimit reports what was set, so returning the guest soft limit alone could report up to INT_MAX for a table of about 122880 descriptors, and a closefrom-style loop up to that value would run billions of iterations instead of about 122k. Return the smaller of the guest soft limit and the host's ::getdtablesize(), which is the FreeBSD sys_getdtablesize result. The guest test derives its expectation from the host call instead of the implementation's formula, and the debt entry no longer claims the limit is raised when libkernel loads outside Linux. Reported by jotitadev in review of the getdtablesize implementation.
Equivalent descriptor reloads in loops must retain runtime table planning. Reuse the existing invariant proof and cover accepted and varying descriptor cases.
The SRT evaluator records every raw read with the user-data word its address is
based on, and marks a word used as a plain value. The result also names the
user-data word behind each shader-data dword.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
The disk cache keeps loaded and persisted entries mapped for the life of
the process. On Windows 10 DeleteFileW refuses a file that still has a
mapped view with ERROR_ACCESS_DENIED, so agc_shader_disk_cache failed in
its final remove_all after every check had passed and left its directory
in the temp folder.
Delete each file with FILE_DISPOSITION_FLAG_POSIX_SEMANTICS before
removing the directories, as WriteFileAtomically already renames with
POSIX semantics. The mapped views stay valid, and the test still fails
when a file or the directory cannot be removed. Linux is unchanged.
A static, read-only image slot whose T# has TYPE 1 is now bound as a null
image, like TYPE 0 since #5473 and #4779. On gfx1010, image_sample_lz,
image_sample_b, image_load and image_get_resinfo through a format-22
TYPE 1 T# return zeros without a fault, and gfx1035 reads it as zeros
too. Written, atomic and table slots still throw, and the reserved
types 2-7 stay refused.
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
mergeBesideReturns ignores the edges into blocks that only lead to a return
when it looks for the merge of a selection whose arms do not meet. It only
recognized a straight run of single-predecessor blocks ending in a return,
so an arm whose return path branches again (an early return inside a
nested if/else) still counted as a block of its own, the arms had no
common post-dominator, and the whole program fell back to flag
structurization ("conditional block 0 has no structured merge").
A block now returns when it has one predecessor, is dominated by the
header and every successor returns. Flag structurization turns every
original block into a guarded region, and the register phis at the region
joins carry values from paths that never reach a later use: in Resident
Evil 4 (PPSA07411) pixel program 0x20762add00 the T# of an image_load
became Phi(0, load through Phi(user data, compare mask)) and resource
analysis refused it. Structured, the T# is the load through the user-data
pointer and the program prepares, captures and materializes.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Morrowind imports fchown and stops at it once rtprio_thread and the pthread concurrency controls are in. Accept the guest's own owner and group (0) or unchanged (-1), fail an invalid descriptor with EBADF, and throw for another owner or group, since ownership is not modelled.
UnchangedSince and UnchangedSinceAll answered by the stamps of the 64 KiB blocks a range
touches, so a CPU or driver store anywhere in a shared block failed every unchanged proof
over it. When a block's stamp is newer, they now look at what wrote the block: the CPU page
stamps over the range and the block's driver-store pieces, as StoredOver does.
For that answer to see every driver stamp, the walk after an own store stamps the pages it
finds dirty in a page map of their own. The unchanged proofs count those pages, so a guest
store beside the stored bytes in the same page is not hidden. StoredOver counts them only in
a block without driver pieces: where pieces exist it answers as before. They take no
driver-piece slot and do not count for the complete coverage StoredAllSince proves. On
Windows, a private mapping made over a block that has driver pieces marks them as
forgotten instead of dropping them.
StoredOver no longer answers stored over for a block whose newer stamp comes only from CPU
stores to other pages.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
The NeighbourCopied case returned Missed as soon as the surface image was
live with nothing pending, although its result had not reached guest
memory yet. It now waits until the result is pending or stored, as
HoldPending does, and only a stored result is a miss.
Fixes#6383
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Since 682b07eb0, an image whose dword 3 wasn't captured is poisoned
(OutsideSnapshot). A record selected past the end of its heap reads
nothing there, so it was poisoned instead of selecting a null image, and
agc_shader_bindless and agc_driver_image_table failed after the merge of
main. A scalar buffer load returns zeros past the end of the buffer, so
those dwords now count as read zeros, and the dwords the selection reads
count as captured. Every other path keeps main's rule.
The guest reader took a module's import modules only from 0x61000045,
the PS5 needed-module tag. PS4 modules list them in 0x6100000f
(DT_SCE_NEEDED_MODULE), so every import of a PS4 module had no library
and bound to any guest export with its NID. In the libc.prx and
libSceFios2.prx that Until Dawn (CUSA02636) bundles, a libc.prx import
then bound to libSceFios2.prx, and the conversion failed with "Cyclic
guest initialization dependency: libSceFios2.prx".
The reader now also reads 0x6100000f, with the same layout (module ID
in bits 48-63, name offset in the low 32 bits). A module that has both
tags fails with "Guest module mixes PS4 and PS5 needed-module tags".
Co-Authored-By: Claude Opus 5.5 <[email protected]>
The headless device is replaced by the windowed one at window attach and then only
lingers for in-flight workers, but it parsed its own full copy of the cache file.
It now starts empty (it still merges what it compiles into the file). Load reuses
the file buffer as the initial data instead of copying it, and save() writes the
live data directly when the file still carries the header this object loaded or
wrote, skipping the read-back and the merge cache.
Use the registered application allocator and the source-backed alignment/size signature. Add callback ownership and failure checks; record unmeasured console behavior.
The kernel maps a dma-buf import's pages for the GPU at the first submission that uses it. On RADV
that took about 2 s for a 3 GiB import, in the second frame of Hades (PPSA03355), and its staging
pool ran out while the frame was held.
Linux now makes the settle queue from #6060 when the device imports dma-buf memory, and settles
every dma-buf import of 1 MiB or more right after it is made with settleImport's 4-byte copy. The
settle queue needs neither the GPU mutex nor the main queue's work to finish. A dma-buf import's
buffer is shared with the settle queue's family instead of aliased, since a sparse import is bound
to many memory objects. Where the sparse queue already takes that family, the settle queue is a
second queue of it.
A guest S# with FILTER_MODE min or max and an anisotropic XY filter
threw "combines a min or max reduction with anisotropic filtering",
which stops High on Life (PPSA15388) in its home base. It now decodes
to a Vulkan sampler with both anisotropy and the reduction mode, as a
weighted-average anisotropic S# already does. RADV programs the same
S# for such a Vulkan sampler.
Tamalero's gfx1030 measurement on #5156 covers a sample without
derivatives through a 2x anisotropic S# over a single-level texture:
min or max with anisotropic bilinear returns the bilinear minimum or
maximum, and min with anisotropic point the point result. The
execution test checks the bilinear case on the host GPU; the debt
entry records what is not measured.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
A flush stores a storage image's pending results to guest memory and
keeps the 64 KiB blocks the write tracker shows written since the image
was last in sync. An address-based dispatch marks the pages it stored to
only when its batch's completion runs. A flush between the GPU's store
and that completion found the blocks unwritten and stored the image's
older texels over the newer bytes; a CPU-resolved indirect dispatch then
read those texels as its workgroup counts.
FlushPending now looks for an unfinished batch that writes the range or
holds it in an address-based lease (Recorder::PendingWriterSerial).
Batches that already finished are completed first. If the writer is
still unfinished, the flush finishes the in-flight batches up to it, or
syncs when the writer is in the open batch, so its marks land and its
blocks are kept. Inside a completion action it does not wait. If the
wait throws, the images it took stay registered as pending.
The test stores an image, then a global dword into the image's memory,
and flushes the image twice: once with the writer's batch finished on
the GPU but its completion not run, and once with the writer still in
the open batch. Each time the dword is kept and a texel in another block
is stored. Without write watching the in-flight case is skipped; the
open-batch case still runs, as the write-back then compares guest
memory, which the GPU has not written yet at the flush.
Co-Authored-By: Claude Opus 5.5 <[email protected]>