Declarative Pipeline Builder¶
Status: migration complete¶
The old per-pass create_*_pipeline factory zoo has been fully retired
(decision C, approved). Every graphics pipeline in the engine is now created
through a single declarative path:
from simvx.graphics.gpu.pipeline import PipelineSpec, build_pipeline
spec = PipelineSpec(name="...", ...) # immutable description
pipeline, layout = build_pipeline(device, spec, render_pass, extent,
vert_module=..., frag_module=...)
A render pass declares what pipeline it wants via an immutable PipelineSpec
and never touches ffi.new itself. build_pipeline composes the private
_make_* sub-struct builders so there is exactly one shared creation path, and
owns all cffi lifetime internally (every sub-struct is rooted in a local keep
list that stays reachable across vkCreatePipelineLayout and
vkCreateGraphicsPipelines). Callers never root a sub-struct by hand.
render_pass, extent, and the optional pre-created shader modules are
late-bound arguments to build_pipeline rather than spec fields, so one
immutable spec can be rebuilt against a different render pass (e.g. the HDR
R16G16B16A16_SFLOAT offscreen pass vs the swapchain B8G8R8A8_SRGB pass)
without copying.
Factories retired (converged onto build_pipeline + inline PipelineSpec)¶
The following module-level factories formerly lived in gpu/pipeline.py and
have been deleted (no compatibility shim or alias). Their config now lives as an
inline PipelineSpec at the call site:
create_forward_pipeline,create_transparent_pipeline,create_skinned_pipeline-> forward / transparent / skinned mesh specscreate_pick_pipeline-> picking (picking/pick_pass.py)create_line_pipeline-> debug-line overlay (renderer/overlay_renderer.py)create_gizmo_pipeline-> editor gizmo overlays (renderer/gizmo_pass.py)create_ui_pipeline,create_textured_quad_pipeline-> 2D fill / line / textured-quad pipelines (renderer/draw2d_pass.py)create_graphics_pipeline-> the generic monolith; removed entirely_Draw2DPipelineSpec/_build_draw2d_pipeline-> the bespoke Draw2D builder; replaced byPipelineSpec+build_pipeline
All render passes now build through this path: skybox, taa, bloom, particle,
text, tilemap, grid, shadow, point_shadow, velocity, depth_prepass, draw2d,
gizmo, overlay (debug lines), pick, and the forward/transparent/skinned mesh
pipelines (renderer/pipeline_manager.py).
Inert-state normalization¶
Pipelines that previously declared front_face = CLOCKWISE together with
cull_mode = NONE were normalized to the PipelineSpec default
(VK_FRONT_FACE_COUNTER_CLOCKWISE). With culling disabled, winding order is
never consulted, so this is GPU-equivalent (pixel-identical, max abs diff 0).
Allowed exception: outline_pass¶
renderer/outline_pass.py keeps its hand-rolled vkCreateGraphicsPipelines
call (a two-pass stencil silhouette pipeline with stencil state that
PipelineSpec deliberately does not model). This is the single sanctioned
exception, and it lives in outline_pass.py, not in gpu/pipeline.py.
Final public API (simvx.graphics.gpu.pipeline)¶
__all__:
PipelineSpec– frozen dataclass describing the varying fixed-function / layout state (topology, vertex input, rasterization, depth/stencil, blend, set layouts, push constants). Everything constant across every surveyed pass (polygon mode FILL, line width 1.0, 1x MSAA, entry point"main", dynamic viewport + scissor) is fixed insidebuild_pipelineand is not a spec field.build_pipeline(device, spec, render_pass, extent, *, vert_module=None, frag_module=None) -> (VkPipeline, VkPipelineLayout)– the single high-level creation entry point.create_shader_module(device, spirv_path) -> VkShaderModuleShared fragments:
FORWARD_VERTEX_STRIDE,FORWARD_VERTEX_ATTRS,SKINNED_VERTEX_STRIDE,SKINNED_VERTEX_ATTRS,POS_COLOUR_VERTEX_STRIDE,POS_COLOUR_VERTEX_ATTRS,UI_VERTEX_STRIDE,UI_VERTEX_ATTRS,MESH_PUSH_CONSTANT_SIZE.
Private primitives (not exported): _make_shader_stages, _make_vertex_input,
_make_empty_vertex_input, _make_input_assembly, _make_viewport_state,
_make_rasterization, _make_multisample, _make_depth_stencil,
_make_colour_blend_opaque / _alpha / _none, _make_dynamic_state,
_create_pipeline_layout, _build_pipeline.
No pass-specific create_*_pipeline factory remains in gpu/pipeline.py.