simvx.graphics.gpu.capabilities

Unified, immutable render-capability snapshot (Vulkan backend).

RenderCapabilities is built once during init_vulkan after device selection and holds probed facts only about the host interpreter and the selected GPU. It subsumes the former _query_device_features dict: there is one capability object, read identically everywhere, with no shim.

The web backend mirrors this shape in packages/web/src/simvx/web/runtime/js/capabilities.js (Capabilities): both expose a meets() predicate with the same truth-table semantics so a pass can gate on {features, limits} regardless of backend.

Probing is deliberately separated from the dataclass. The module-level probe helpers take raw Vulkan handles and return plain scalars; the frozen dataclass is constructible directly from those scalars. Unit tests therefore build a RenderCapabilities from injected values with no GPU, and only the probe classmethod touches Vulkan.

Module Contents

Classes

RenderCapabilities

Immutable snapshot of host + GPU render capabilities.

Functions

probe_free_threaded

True when the running interpreter has the GIL disabled (free-threaded).

probe_gil_disabled_build

The Py_GIL_DISABLED build-config flag (the interpreter was built free-threaded), independent of whether the GIL is currently re-enabled at runtime via PYTHON_GIL=1.

probe_device_features

Query the optional Vulkan device-feature bits SimVX cares about.

probe_physical_device_count

Number of Vulkan-capable physical devices on this instance.

probe_device_group

Whether linked device groups (VK_KHR_device_group / 1.1 core) are usable on this instance.

probe_external_memory_fd

Whether VK_KHR_external_memory_fd is exposed by the device.

probe_dedicated_queue_families

Locate dedicated compute and transfer queue families.

probe_gpu_timing

Whether the device supports GPU timestamp queries (timestampPeriod > 0).

Data

API

simvx.graphics.gpu.capabilities.__all__

[‘RenderCapabilities’, ‘probe_free_threaded’, ‘probe_gil_disabled_build’, ‘probe_device_features’, ‘…

simvx.graphics.gpu.capabilities.log

‘getLogger(…)’

simvx.graphics.gpu.capabilities.probe_free_threaded() bool[source]

True when the running interpreter has the GIL disabled (free-threaded).

sys._is_gil_enabled() exists only on builds that know about the flag (3.13+); older builds are always GIL-enabled, so absence -> not free-threaded.

simvx.graphics.gpu.capabilities.probe_gil_disabled_build() bool[source]

The Py_GIL_DISABLED build-config flag (the interpreter was built free-threaded), independent of whether the GIL is currently re-enabled at runtime via PYTHON_GIL=1.

simvx.graphics.gpu.capabilities.probe_device_features(physical_device: Any) dict[str, bool][source]

Query the optional Vulkan device-feature bits SimVX cares about.

Returns a plain dict[str, bool] so the logical-device creation path can request exactly the features the device reports (see create_logical_device). RenderCapabilities.probe folds the same dict into typed fields.

simvx.graphics.gpu.capabilities.probe_physical_device_count(instance: Any) int[source]

Number of Vulkan-capable physical devices on this instance.

simvx.graphics.gpu.capabilities.probe_device_group(instance: Any) bool[source]

Whether linked device groups (VK_KHR_device_group / 1.1 core) are usable on this instance.

vkEnumeratePhysicalDeviceGroups may be unresolvable through the loader on an instance created without the right API version / extension (observed on the dev box’s Iris Xe + 1.2 loader path); we catch that and yield False rather than letting an unresolvable-proc error escape init.

simvx.graphics.gpu.capabilities.probe_external_memory_fd(physical_device: Any) bool[source]

Whether VK_KHR_external_memory_fd is exposed by the device.

Gates the dma-buf zero-copy cross-device transfer path (D8 multi-GPU). The extension must also be enabled at logical-device creation to be usable; the probe only reports availability. Absent on this dev box -> the staging-copy floor is always chosen.

simvx.graphics.gpu.capabilities.probe_dedicated_queue_families(physical_device: Any) tuple[int | None, int | None][source]

Locate dedicated compute and transfer queue families.

Returns (dedicated_compute_qf, dedicated_transfer_qf):

  • dedicated compute: a family with COMPUTE but not GRAPHICS (async compute),

  • dedicated transfer: a family with TRANSFER but neither GRAPHICS nor COMPUTE (DMA-only copy engine). COMPUTE/GRAPHICS families implicitly support transfer, so we want the genuinely transfer-only one.

Either is None when the device exposes no such family (e.g. integrated GPUs with a single universal queue family).

simvx.graphics.gpu.capabilities.probe_gpu_timing(physical_device: Any) bool[source]

Whether the device supports GPU timestamp queries (timestampPeriod > 0).

class simvx.graphics.gpu.capabilities.RenderCapabilities[source]

Immutable snapshot of host + GPU render capabilities.

Probed facts only: no policy, no derived “should we” decisions. Consumers (the renderer, the future threading/queue/multi-GPU paths) read these fields and decide. Build via :meth:probe at init, or construct directly from scalar fields in tests.

free_threaded: bool

False

GIL is disabled at runtime (not sys._is_gil_enabled()).

gil_disabled_build: bool

False

Interpreter was built free-threaded (Py_GIL_DISABLED config var).

physical_device_count: int

1

device_group: bool

False

A linked device group with >1 physical device is available.

external_memory_fd: bool

False

VK_KHR_external_memory_fd is available (probed) on the selected device.

Availability only: it does not mean the extension was enabled at logical-device creation. Use :attr:external_memory_fd_enabled to gate the dma-buf zero-copy path; this field reports whether enabling it is even possible. False on this dev box.

external_memory_fd_enabled: bool

False

VK_KHR_external_memory_fd was enabled at logical-device creation.

This is the gate the D8 multi-GPU cross-device transfer reads to select the dma-buf zero-copy path (:mod:simvx.graphics.gpu.multi_device): a probed-but- not-enabled extension cannot export/import fds, so DMABUF stays unselected and the always-available staging-copy floor is used until the rig opts in and the secondary + primary devices both enable it. False on this dev box (the single-GPU path never requests it), so the dma-buf raise is never reached.

dedicated_compute_qf: int | None

None

dedicated_transfer_qf: int | None

None

gpu_timing: bool

False

multi_draw_indirect: bool

False

image_cube_array: bool

False

texture_compression_bc: bool

False

texture_compression_etc2: bool

False

texture_compression_astc_ldr: bool

False

limits: dict[str, int]

‘field(…)’

meets(*, features: list[str] | None = None, limits: dict[str, int] | None = None) bool[source]

Predicate mirroring the web Capabilities.meets() truth table.

features are capability field names that must be truthy (e.g. "multi_draw_indirect", "free_threaded", "gpu_timing"). limits maps a GPU-limit key to a minimum required value; every requested limit must be present and >= the requested value. Empty requirements pass. An unknown feature name fails (a typo never silently passes), matching the web has() semantics.

classmethod probe(instance: Any, physical_device: Any) simvx.graphics.gpu.capabilities.RenderCapabilities[source]

Build a capability snapshot from live Vulkan handles + the host build.

Pure probing: all GPU access is delegated to the module-level probe_* helpers so this stays the single Vulkan touch point.