A WAIT_REG_MEM_64 whose mask leaves the high dword out compares the low
dword alone, but the wait paths looked for all eight bytes: the
recorder's label table and the stores committed since the submission
want an entry for each dword, while a producer's RELEASE_MEM or
WRITE_DATA stores 32 bits, so neither ever satisfied such a wait, and the
held-at-submission check refused it when an earlier packet stored the
unrelated high dword.
Pm4::WaitAwaitedBytes gives the bytes that decide the compare (4 for
WAIT_REG_MEM and for a WAIT_REG_MEM_64 whose high mask dword is zero,
else 8), and the wait paths use it. The timeout report now prints a
64-bit wait's reference and mask (it printed the reference's two halves
as "ref" and "mask").
A title may reclaim a label (reset it to 0) as soon as the submission
that released it is done, trusting every queue waiting on it to have
passed its WAIT_REG_MEM within microseconds, as the CP polls from the
moment it reaches the wait. A worker that reaches a later wait of the
same submission long after (it records and compiles in between) found
the reset label and timed out.
A memory wait now also passes when
- a label store the driver committed (recorded on the GPU, as a
completion action, or on the CPU) after the wait's submission gave the
awaited bytes a value the wait accepts (the last four stores per dword,
with their eventSerial stamps). Such a store belongs to this use of the
label or a later one, since the title reset it before submitting.
- the awaited bytes held such a value when the game submitted, and no
earlier packet of the queue (in the submission, or one still queued or
running) stores to them.
A store made before the submission never satisfies a wait.
sceAgcDriverAddEqEvent and sceAgcDriverDeleteEqEvent were NotImplemented,
so a title that waits on its equeue for the GPU to reach the end of a
command buffer could never be woken.
AddEqEvent now registers a graphics-core event (filter -14, ident = the
given id, EV_CLEAR, data counting the interrupts since the last wait) on
the kernel equeue and remembers the registration; DeleteEqEvent removes
both. An invalid equeue or deleting an event that is not registered
throws.
The driver delivers the interrupt when it executes a RELEASE_MEM whose
INT_SEL is non-zero. Such a packet is not deferred as a GPU label: the
recorded work before it is drained, its memory write (if any) is done,
and then the event registered with the id of the issuing queue is
triggered (0 for the graphics ring, the ACB queue id for compute), which
matches how titles derive their event ids from the ring they submit on.