simvx.core.scene_target_graph¶
SceneTargetGraph: inter-scene render-target dependency scheduler.
design/render_parallelism_and_multi_gpu.md P1-2. Where RenderGraph
(graphics package) orders named passes within one scene render, this graph
orders whole scene render jobs, one per offscreen target (each SubViewport,
and later each RenderView) plus the main scene, so a producer target renders
before any job that samples it in the same frame.
Jobs register the way RenderGraph passes do: :meth:SceneTargetGraph.add
then :meth:SceneTargetGraph.compile. Edges are texture-sampling
dependencies, expressed two ways:
implicit: a job
consumesbindless slot integers; the job thatproducesthat slot must come first (mirrorsRenderGraph’s named string resources, with bindless slots as the resource names);explicit:
afterlists producer job names (thefeeds_fromhint and the main scene’s “after every offscreen target” barrier).
Both graphs share the one Kahn implementation in
- mod:
simvx.core._topo_sort(P1-1, no fork). Cycle policy differs by design: an intra-scene pass cycle is a bug (RenderGraphraises), but an inter-scene cycle (mirror facing mirror) is legitimate, socompilenever raises: Tarjan SCC drops the minimal back-edge(s) and reports them as- attr:
lagged_edges, each sampling the previous frame’s target, scoped to the cyclic boundary. Under serial per-target execution a lagged edge is automatically correct (the previous frame’s content is fully resident).
Compilation is fingerprint-cached: re-registering an identical job set (the
steady-state frame) reuses the previously computed order without re-sorting.
The sort therefore runs on a structure change (a target added/removed, a slot
assigned, a sampling binding changed), not per frame. Consumed-slot
detection stays with the caller (order_subviewports scans subtrees),
because a sampling binding such as material.albedo_tex_index can change
without bumping the tree’s structure version.
Dependency-light on purpose (imports nothing from simvx.graphics): the
web backend orders its offscreen targets through the same code path.
Module Contents¶
Classes¶
One scene render job: an offscreen target (or the main scene). |
|
Orders scene render jobs so producer targets render before consumers. |
Data¶
API¶
- simvx.core.scene_target_graph.log¶
‘getLogger(…)’
- simvx.core.scene_target_graph.__all__¶
[‘SceneJob’, ‘SceneTargetGraph’]
- class simvx.core.scene_target_graph.SceneJob(name: str, *, node: Any = None, produces: int = -1, consumes: collections.abc.Iterable[int] = (), after: collections.abc.Iterable[str] = ())[source]¶
One scene render job: an offscreen target (or the main scene).
Args: name: Unique job name (deterministic across frames for a stable structure, so the compile cache holds). node: The owning scene node (a SubViewport), or
Nonefor the main scene job. Carried through so :attr:SceneTargetGraph.ordermaps straight back to nodes. produces: The bindless slot this job renders into, or-1when it publishes no sampleable target (the main scene, a first-frame target with no slot yet). consumes: Bindless slots sampled inside this job’s scene. Slots no registered job produces are ignored (dangling inputs are allowed, as inRenderGraph: the resource comes from outside the graph). after: Names of jobs that must render first, regardless of slots (explicitfeeds_fromhints; the main scene’s barrier). Unknown names are ignored.Initialization
- __slots__¶
(‘name’, ‘node’, ‘produces’, ‘consumes’, ‘after’)
- class simvx.core.scene_target_graph.SceneTargetGraph[source]¶
Orders scene render jobs so producer targets render before consumers.
Usage (mirrors
RenderGraph)::graph = SceneTargetGraph() graph.clear() # start a (re-)registration graph.add(SceneJob("svp:12", node=svp, produces=12, consumes={13})) graph.add(SceneJob("svp:13", node=other, produces=13)) graph.add(SceneJob("scene:main", after=("svp:12", "svp:13"))) graph.compile() # sorts only if the structure changed for job in graph.order: ... graph.lagged_edges # broken cycle edges, usually emptyInitialization
- __slots__¶
(‘_jobs’, ‘_fingerprint’, ‘_order_idx’, ‘_lagged_idx’, ‘_compile_count’)
- add(job: simvx.core.scene_target_graph.SceneJob) None[source]¶
Register a job. Call before :meth:
compile. Duplicate names are an error.
- compile() bool[source]¶
Topologically sort the registered jobs; producers first, never raises.
Fingerprint-cached: when the registered jobs describe the same structure as the previous compile (same names, slots, sampled slots and explicit edges, in the same registration order), the cached order is remapped onto the current job objects without re-sorting. Returns
Truewhen a real sort ran,Falseon a cache hit.
- property order: tuple[simvx.core.scene_target_graph.SceneJob, ...][source]¶
Compiled render order (producers first).
- property lagged_edges: frozenset[tuple[simvx.core.scene_target_graph.SceneJob, simvx.core.scene_target_graph.SceneJob]][source]¶
(producer, consumer)edges broken to resolve cycles (1-frame lag).
- property jobs: tuple[simvx.core.scene_target_graph.SceneJob, ...][source]¶
Registered jobs, in registration order.