Ports the event-queue rework from the archived silent-hill-minimal branch
(968e9606, 9e3abb12, 2be9cfbf, f157a115) onto current upstream. The equeue
implementation had not been touched upstream since that branch forked, so
none of it had landed.
Behaviour fixed:
- Per-waiter event reservation. A blocked waiter used to wake on "the queue
has any pending event" (TryWake => HasPendingEvents) and then re-read the
queue on resume, so a woken waiter could find the event already drained by
another waiter and park again with the wake consumed. Events are now
reserved to the waiter they are delivered to.
- Level-triggered events are preserved instead of being cleared by an
unrelated read; only events that declare clear-on-read reset their trigger
state.
- Queued interrupts are bound to the registration generation that produced
them, so an event registered after a queue was reused cannot consume an
interrupt raised for the previous registration.
- Deleting an equeue now terminates its waiters instead of leaving them
blocked on a handle that no longer resolves.
- sceKernelTriggerUserEvent stores its third argument in the event's udata
(0x18) rather than its data word (0x10). The guest reads it back with
sceKernelGetEventUserData, which loads 0x18, so every triggered user event
previously read back as 0. This matches the reference behaviour in shadPS4,
where TriggerEvent takes udata and sceKernelGetEventUserData returns
ev->udata. The upstream test asserting the data word is updated, since it
encoded the inconsistency rather than the ABI.
KernelPthreadState gains TryGetCurrentThreadIdentity and a new
KernelSyncTraceFormatter carries the shared, opt-in diagnostic formatting the
ported code calls; both are gated behind the existing trace flag and do no
work when it is off.
Tests: 662 pass, 0 fail (SharpEmu.Libs.Tests 588 -> 598).
sceAgcDriverSubmitAcb submissions never produced a completion interrupt.
NotifySubmittedDcbCompleted returned early for anything that was not the
graphics queue, so an ACB reaching its ordered-queue fence published
nothing. UE 4.27's dynamic-resolution GPU-timing heuristic parks the game
thread on exactly that interrupt, so the render side never advanced and
Silent Hill: The Short Message deadlocked after its first frame.
Give every queue a CompletionEventId: 0 for graphics (what it already
published) and the owner handle from sceAgcDriverSubmitAcb rdi for a
compute queue, which is the same value the guest passes to
sceAgcDriverAddEqEvent. Publish under that ident from the existing fence
point, which both PumpSubmittedQueue and ResumeSuspendedDcb already reach
only after the submission is fully parsed.
Delivery is synchronous on the ordered guest-action queue rather than on a
ThreadPool hop with a sleep. That action runs after the logical queue has
flushed and waited for its latest fence, which is the moment hardware
would raise end-of-pipe. Deferring past it can only make the interrupt
late and reorder it against registration changes.
Gating: the per-queue completion event is unconditional, because
completion interrupts do fire on real hardware and because delivery is
registration-gated -- TriggerRegisteredEvents only queues onto equeues
that registered this exact (ident, graphics filter) pair, and
sceAgcDriverAddEqEvent is the only producer of graphics registrations. A
title that never registers its ACB owner handle observes no change.
SHARPEMU_AGC_SUBMIT_COMPLETION_EVENT is left to gate only the broad
ident-ignoring fan-out (TriggerRegisteredEventsDistinct), which is a
compatibility guess rather than hardware behavior; it also stays scoped to
the graphics queue where it was measured, so enabling the flag does not
newly fan out across compute queues.
* [HLE] Trigger AGC graphics events by filter instead of exact ident (#173)
The PM4 EVENT_WRITE packet carries a 6-bit hardware EVENT_TYPE, but the
guest registers AGC events via sceAgcDriverAddEqEvent with a full guest
eventId. These two values are not the same numbering scheme, so the exact
ident lookup in TriggerRegisteredEvents never matched and the AGC
interrupt thread hung forever.
Add TriggerRegisteredEventsByFilter, which wakes every graphics event
registration on every queue. This is a compatibility workaround for
issue #173 while the real PS5 mapping remains unknown.
Includes unit tests covering the mismatched ident/eventType case.
* [HLE] Fix POSIX condition variable semantics (#113)
Remove PendingSignals from PthreadCondState. POSIX condition signals are edges,
not semaphore credits - a signal with no waiter must have no effect. The previous
implementation persisted signals, causing lock inversions and predicate bypasses.
Changes:
- Remove PendingSignals property and TryConsumePendingSignal method
- Remove pending signal consumption logic from PthreadCondWaitCore
- Remove PendingSignals increment from PthreadCondSignalCore
- Add regression tests verifying POSIX-correct behavior
Fixes#113