Turning Command Buffers into Vulkan Work

AnyPS5's graphics path begins with work submitted by the title and ends with commands recorded for a host Vulkan device. The important question is what happens between those endpoints: how command-buffer state becomes a validated draw or dispatch, how guest memory becomes usable resources, and how a host device decides whether the work can run directly or needs a fallback. Following one draw makes the graphics boundary concrete and shows why memory residency, alias checks, shaders, and synchronization belong in the same lifecycle.

From command submission to a validated draw

The architecture documentation describes the graphics path through libSceAgcDriver: title command buffers are submitted, PM4 execution reconstructs state and draw or dispatch operations, and the result is translated into Vulkan work. A command packet is not yet a host API call. It carries state that must be interpreted in the context of the current guest memory, shader stages, render targets, resource descriptors, and device capabilities.

The driver first validates the operation that the packet describes. For a draw, that can include whether the draw is indexed, whether the index size is supported, whether counts and ranges overflow, whether the index buffer overlaps the render target, and whether a mesh or tessellation path has the required primitive shape. It validates the viewport and depth state against the selected Vulkan device's limits. An invalid packet is rejected before it becomes a host command because recording a syntactically valid Vulkan draw would not make the guest operation valid.

The state being reconstructed includes more than the draw count. The driver must know which shader stages are active, which color and depth targets are bound, what topology and culling state apply, how the viewport and scissor constrain the work, and which descriptor words identify buffers, images, and samplers. Some of these values arrive through command packets, while others are held in the current AGC state. A draw is meaningful only after those pieces have been combined into one snapshot.

That combination is also where guest and host limits meet. A guest index range can be numerically valid but exceed the selected device's indexed-draw limit. A mesh draw can describe more workgroups than the host permits. A viewport can contain a non-finite value or exceed the device bounds. The driver validates the guest request against the host limits it has selected, so it can reject a state that is meaningful on the source platform but cannot be represented safely by the current Vulkan device.

Index and vertex data then cross the memory boundary established in the previous chapter. AnyPS5 can reuse a previously prepared host buffer when the guest allocation and its write generation still match. Otherwise, it copies the guest range into a host-side buffer with the appropriate vertex or index usage. For an indexed draw, it can read the copied indexes to determine the highest referenced vertex and limit the vertex data that must be prepared. The copy is not an arbitrary optimization: it gives the host GPU a safe buffer while keeping the guest address and freshness checks explicit.

Indirect draws add another decision. If the host can see the argument records through a valid import, the driver can record a Vulkan indirect operation. If a guest rule requires a constant to be applied or the host lacks a needed indirect feature, AnyPS5 can copy or rewrite the argument records, or read them on the CPU and issue ordinary draws. The result remains a draw, but its execution path changes with the memory and feature conditions available on the host.