simvx.graphics.gpu.pipeline

Graphics pipeline and shader module management.

Module Contents

Classes

PipelineSpec

Declarative description of a graphics pipeline’s varying state.

Functions

create_shader_module

Load a SPIR-V file and create a VkShaderModule.

build_pipeline

Create a (VkPipeline, VkPipelineLayout) from a declarative spec.

Data

API

simvx.graphics.gpu.pipeline.log

‘getLogger(…)’

simvx.graphics.gpu.pipeline.__all__

[‘PipelineSpec’, ‘VertexAttr’, ‘VertexBinding’, ‘build_pipeline’, ‘create_shader_module’, ‘POS_COLOU…

simvx.graphics.gpu.pipeline.VertexAttr

None

simvx.graphics.gpu.pipeline.VertexBinding

None

simvx.graphics.gpu.pipeline.MESH_PUSH_CONSTANT_SIZE

132

simvx.graphics.gpu.pipeline.POS_COLOUR_VERTEX_STRIDE

28

simvx.graphics.gpu.pipeline.POS_COLOUR_VERTEX_ATTRS: tuple[simvx.graphics.gpu.pipeline.VertexAttr, ...]

((0,), (1,))

simvx.graphics.gpu.pipeline.UI_VERTEX_STRIDE

32

simvx.graphics.gpu.pipeline.UI_VERTEX_ATTRS: tuple[simvx.graphics.gpu.pipeline.VertexAttr, ...]

((0,), (1,), (2,))

simvx.graphics.gpu.pipeline.UI2D_VERTEX_STRIDE

40

simvx.graphics.gpu.pipeline.UI2D_VERTEX_ATTRS: tuple[simvx.graphics.gpu.pipeline.VertexAttr, ...]

((0,), (1,), (2,), (3,), (4,))

simvx.graphics.gpu.pipeline.create_shader_module(device: Any, spirv_path: pathlib.Path) Any[source]

Load a SPIR-V file and create a VkShaderModule.

class simvx.graphics.gpu.pipeline.PipelineSpec[source]

Declarative description of a graphics pipeline’s varying state.

Captures only the fixed-function and layout state that genuinely differs between SimVX’s render passes; everything constant across every surveyed pass (polygon mode FILL, line width 1.0, 1x MSAA, entry point "main", dynamic viewport + scissor) is fixed inside :func:build_pipeline.

The render pass, framebuffer extent, and (optionally) pre-created shader modules are late-bound arguments to :func: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.

Vertex input: either the legacy single-binding pair (vertex_stride + vertex_attrs, binding 0) or the multi-binding vertex_bindings tuple of (binding, stride, attrs) triples with explicit (possibly sparse) Vulkan binding numbers (vertex stream split, D5). The two forms are mutually exclusive; the :attr:vertex_input_bindings property presents both uniformly. vertex_stride == 0 with no vertex_bindings selects an empty vertex input state (geometry generated in the shader).

Colour blend: "opaque" (no blending), "alpha" (src-alpha / one-minus-src-alpha), "add" (additive, src.a-scaled over ONE), "multiply" (dst * src), or "none" (zero colour attachments, for depth-only passes). attachment_count (default 1) replicates the blend state across that many colour attachments for multi-render-target passes (thin G-buffer, D3); it must stay 1 when blend is "none".

name: str

None

vert_spirv: pathlib.Path | None

None

frag_spirv: pathlib.Path | None

None

topology: int

None

vertex_stride: int

0

vertex_attrs: tuple[simvx.graphics.gpu.pipeline.VertexAttr, ...]

()

vertex_bindings: tuple[simvx.graphics.gpu.pipeline.VertexBinding, ...]

()

cull_mode: int

None

front_face: int

None

depth_bias: tuple[float, float] | None

None

depth_test: bool

True

depth_write: bool

True

depth_compare: int

None

blend: Literal[opaque, alpha, add, multiply, none]

‘opaque’

colour_write_mask: int

None

dst_alpha_factor: int

None

attachment_count: int

1

writes_gbuffer: bool

False

set_layouts: tuple[Any, ...]

()

push_size: int

0

push_stages: int

‘field(…)’

__post_init__() None[source]
property vertex_input_bindings: tuple[simvx.graphics.gpu.pipeline.VertexBinding, ...][source]

The vertex input as a binding tuple, whichever form the spec used.

Empty means no vertex buffers (shader-generated geometry). The legacy single-binding fields wrap into a one-entry tuple so both forms build identical pipelines through one path.

simvx.graphics.gpu.pipeline.build_pipeline(device: Any, spec: simvx.graphics.gpu.pipeline.PipelineSpec, render_pass: Any, extent: tuple[int, int], *, vert_module: Any = None, frag_module: Any = None) tuple[Any, Any][source]

Create a (VkPipeline, VkPipelineLayout) from a declarative spec.

This is the single high-level pipeline-creation entry point: a render pass declares what pipeline it wants via :class:PipelineSpec and never touches ffi.new itself. Internally it composes the private _make_* sub-struct builders so there is one shared creation path.

Args: device: The VkDevice. spec: The immutable pipeline description. render_pass: The VkRenderPass the pipeline targets (late-bound so one spec can build against the HDR or swapchain pass). extent: (width, height) for the (dynamic) viewport/scissor placeholders required at create time. vert_module / frag_module: Optional pre-created VkShaderModule handles. When supplied, they are used directly and not destroyed by this function (the caller owns them); this serves passes that compile GLSL -> SPIR-V at runtime. When omitted, modules are loaded from spec.vert_spirv / spec.frag_spirv and likewise returned via the pipeline (the caller still owns lifetime).

cffi lifetime: every ffi.new sub-struct is appended to a local keep list that stays reachable for the whole function body, so it is alive across the vkCreatePipelineLayout and vkCreateGraphicsPipelines calls (Vulkan reads pCreateInfos only during those calls). No caller ever has to root a sub-struct by hand. keep only becomes collectable after this function returns, strictly after the create calls have returned.