simvx.graphics.renderer.async_compute¶
Async-compute scheduler: route compute passes to a dedicated queue when one exists.
The renderer records several compute passes per frame (occlusion cull, Hi-Z build, particle simulation, light cull). On a GPU with a dedicated compute queue family (COMPUTE without GRAPHICS), those passes can run on a separate queue and overlap graphics work; the graphics submit then waits on a compute-done semaphore before its consumers (draw-indirect / vertex / depth sample) read the compute results.
AsyncComputeScheduler is the single seam that hides this. Two modes,
selected once at construction from :pyattr:GPUContext.async_compute:
passthrough (no dedicated compute queue, e.g. integrated GPUs / this dev box): :meth:
record_computerecords straight into the primary graphics command buffer the caller passes in, :meth:submitis a no-op, and- meth:
graphics_wait_semaphoresis empty. The frame is byte-identical to the pre-async path: the scheduler adds nothing to the command stream.
async (dedicated compute queue): :meth:
begin_frameopens a per-frame compute command buffer on the compute queue’s pool; :meth:record_computerecords into that buffer (ignoring the graphics cmd argument); :meth:submitends and submits it to the compute queue signalling the frame’s compute-done semaphore; :meth:graphics_wait_semaphoresreturns that semaphore (with its wait stage) so the graphics submit blocks until compute results are visible.
Cross-queue data visibility for the shared control buffers is handled at
buffer-creation time via VK_SHARING_MODE_CONCURRENT (see
GPUContext.concurrent_compute_families and memory.create_buffer); this
scheduler owns only the execution ordering (command buffer + semaphore).
Routing the actual passes through this scheduler is a separate wave; this module provides the gated abstraction and is a no-op until a pass calls
- meth:
record_compute.
Module Contents¶
Classes¶
Records + submits compute passes on a dedicated queue when available. |
Data¶
API¶
- simvx.graphics.renderer.async_compute.__all__¶
[‘AsyncComputeScheduler’]
- simvx.graphics.renderer.async_compute.log¶
‘getLogger(…)’
- class simvx.graphics.renderer.async_compute.AsyncComputeScheduler(ctx: simvx.graphics.gpu.context.GPUContext, frames_in_flight: int)[source]¶
Records + submits compute passes on a dedicated queue when available.
Construct once per Engine.
async_enabledreflects the GPU: whenFalseevery method degrades to the single-queue passthrough.Initialization
- begin_frame(frame_index: int, graphics_cmd: Any) None[source]¶
Open recording for
frame_index.graphics_cmdis the primary command buffer for this frame; in passthrough mode compute passes are recorded into it directly. In async mode it is unused (compute records into the dedicated compute cmd) but is still passed for a uniform call site.
- record_compute(record_fn: collections.abc.Callable[[Any], None]) None[source]¶
Record a compute pass.
record_fn(cmd)issues the dispatch(es) and any intra-compute barriers. In async modecmdis the dedicated compute command buffer; in passthrough mode it is the primary graphics command buffer (so the pass records inline exactly as it does today). Producer->consumer cross-queue ordering is provided by the compute-done semaphore on the async path; the pass’s own intra-queue barriers remain valid in both.
- submit() None[source]¶
Submit the compute command buffer (async) or no-op (passthrough).
In async mode the compute cmd is ended and submitted to the compute queue, signalling this frame’s compute-done semaphore that the graphics submit waits on. With no recorded work the semaphore is still signalled (empty submit) so the graphics wait never deadlocks.
- graphics_wait_semaphores() tuple[list[Any], list[int]][source]¶
Semaphores + per-semaphore wait stages for the graphics submit.
Returns
(semaphores, wait_stages)to merge into the frame’sVkSubmitInfoso the graphics queue blocks on compute results before the indirect-draw / vertex / depth-sample stages consume them. Empty in passthrough mode (no extra wait: identical submit to today).