A wave64 compute or mesh program on a 32-wide host runs two lanes per
invocation, and the emitter emitted every IR value once per lane, scalar ones
included: each SGPR value, scalar memory load and loop phi existed twice in
the module, raising register pressure for every such program.
WaveUniformValues (SpirvAnalysis) finds the values every lane of the wave
computes alike: user data, constants, resources, ballots, readlane and
readfirstlane results, scalar loads through a wave-uniform address, and what
follows from them alone. Lane ids, builtins other than the workgroup id, lane
exchanges and every other memory or image read differ by lane, as does
anything computed from them. For such a value without side effects, the
second lane reuses the first lane's definition. Both lanes are one
invocation, so they share control flow and the definition dominates every
use of the second lane.
agc_shader_memory checks the analysis and that a two-lane module computes a
scalar product as often as the one-lane module. The agc_driver_wave_uniform
execution test runs a wave64 program with a scalar loop, a ballot and a
readfirstlane and checks every lane's result. It skips on a subgroup
narrower than 32, such as lavapipe's.
The [present] line, printed under APS5_PROFILE_DRAW, takes its GPU busy and
idle gaps from the whole-batch timestamps in each batch's completion record.
Those stamps were only written under APS5_PROFILE_GPU, which also times every
command. Under APS5_PROFILE_DRAW alone every batch finished with zero stamps,
so the line read "GPU busy 0.0 ms, idle gaps 0.0 ms" with no missing records.
Under APS5_PROFILE_DRAW each batch now carries just its two batch stamps in a
two-query pool, reused across batches like the command buffers.
APS5_PROFILE_GPU is unchanged, and nothing is written with profiling off.
agc_driver_recorder_tests (GPU, by hand) checks that three consecutive
batches' completion records carry ordered stamps exactly when batch stamps
are on, and none with profiling off.
processFlip set lastFlipVblank to the vblank count after the host present
returned. When the acquire, the wait for an earlier presentation or the
present itself crossed the next vblank, the next flip's target moved out
by one vblank even when that flip was already queued: a frame ready in
17 ms was shown for 33 ms, and a title that advances its logic by a fixed
step per presented frame ran in slow motion.
A flip takes effect at the vblank it is released at, so that vblank is
now the one the next flip's interval counts from, recorded when the flip
is released. Flip events, flipStatus and flipPendingNum are unchanged.
Test: video_out_flip_tests pacing (needs a GPU and a display) submits
the first flip at flip rate 2, whose presentation opens the device and
spans several vblanks, and checks that lastFlipVblank is 3.
A RELEASE_MEM with an interrupt select drained the device: the queue
worker submitted everything recorded and waited for the GPU before it
stored the label and delivered the interrupt. PPSA21564 issues about 300
of them per frame, so the worker and the GPU took turns.
The label is now recorded like any other (on the GPU behind the work, or
as a completion action behind pending write-backs), and the delivery
becomes a completion action of the batch holding the work before the
packet (Recorder::AfterRecordedWork, after the batch's earlier
completions). It is counted with the completion labels, so idle workers
and pollers reap it, and it starts the label flush deadline. With draws
or dispatches recorded since the last submit the batch is submitted at
once. A batch holding only label stores stays open and goes out with the
next work, at the label flush deadline, at a wait, at a flip or at the
end of the submission, like any other pending label. A label the GPU
cannot store, or one that does not decode, still drains.
The interrupt so never arrives before the work ahead of it completed and
its label landed; it can only arrive later, by at most the flush
deadline plus the work recorded into the same batch.
PPSA21564's final composite renders into 4K 10-bit scanout buffers
(COLOR_2_10_10_10 with the alternate swap, A2R10G10B10). No guest texture
format matched that color format, so the target stayed non-resident:
every frame's composite draw ran synchronously (about 11 ms, 143 per 10 s
at the title) and the flip read the frame back through guest memory.
The blue-low 10-bit color target now keeps its bits in the storage image
of its surface's red-low 2-10-10-10 format, as B8G8R8A8 targets map to
R8G8B8A8.
Presenting it: DisplayTexelFormat names a display buffer's texel order as
the guest-memory path reads it (R8G8B8A8 base: red low, else blue low;
the 10-bit variant: A2B10G10R10 or A2R10G10B10). ResidentPresentPath
blits a resident image only when it holds the display's 8-bit texel
format (an exact copy). A 10-bit image (whose blit would round where the
guest path drops the low two bits), the other 8-bit order or an sRGB type
is converted instead: GpuColorTransfer::DetileImage copies the image's
texels raw and runs the guest path's own conversion shader on them, so
both paths present the same pixels.
The image's write-back is unchanged: its results stay pending like any
resident target's and are stored when a reader of the memory flushes
them.
Tests: agc_driver_recorder_tests checks the format decision for both
8-bit and both 10-bit orders, and converts an image in each order,
comparing it with the CPU decode and the GPU detile of the same words in
guest memory.
Replace the decoder-less AvPlayer with a player that demuxes MP4 sources
with FFmpeg (opened by path or through the title's file replacement),
decodes H.264 and AAC on their own threads, and hands out NV12 frames and
interleaved 16-bit PCM in buffers from the title's allocators, presented
on a media clock that audio drives when it is enabled.
Both libSceAvPlayer and libSceAvPlayer.native are built from the same
sources and link the shared ffmpeg target. The struct size checks stay,
next to the types in SceTypes.hpp. ChangeStream and GetStreamInfoEx are
implemented; Init without allocators, StartEx, SetAvailableBandwidth,
SetLogCallback and negative trick speeds succeed as before and are listed
in TechnicalDebt. HLS sources throw.
guest_avplayer plays an embedded 6 KB MP4 (H.264 plus two AAC tracks).