Source code for simvx.graphics.renderer.render_context

"""RenderContext — setup-time GPU facade.

Passes receive this in setup() instead of raw engine references. Consolidates
GPU resource creation entry points and exposes concrete Vulkan handles as plain
attributes. Does NOT wrap per-frame command recording — passes call vk.* directly
inside record().

For a future Metal backend, a MetalRenderContext subclass would hold Metal
equivalents in the same-named attributes.
"""

from __future__ import annotations

import pathlib
from typing import Any

from .resource_registry import ResourceRegistry

__all__ = ["RenderContext"]


[docs] class RenderContext: """Setup-time GPU facade. Created once by ForwardRenderer, passed to pass.setup().""" __slots__ = ( "device", "physical_device", "graphics_queue", "command_pool", "texture_descriptor_layout", "texture_descriptor_set", "resources", "width", "height", "frames_in_flight", "render_pass", "shader_dir", "extent", # Engine back-reference (escape hatch for vendor-specific needs) "_engine", ) def __init__( self, engine: Any, resources: ResourceRegistry, ) -> None: self._engine = engine self.device: Any = engine._device self.physical_device: Any = engine._physical_device self.graphics_queue: Any = engine._graphics_queue self.command_pool: Any = engine._cmd_ctx.pool self.texture_descriptor_layout: Any = engine.texture_descriptor_layout self.texture_descriptor_set: Any = engine.texture_descriptor_set self.resources = resources w, h = engine.extent self.width: int = w self.height: int = h self.extent: tuple[int, int] = (w, h) self.render_pass: Any = engine.render_pass self.shader_dir: pathlib.Path = engine.shader_dir from .._types import FRAMES_IN_FLIGHT self.frames_in_flight: int = FRAMES_IN_FLIGHT # -- Resource creation helpers (thin delegates to existing gpu/* functions) --
[docs] def create_buffer( self, size: int, usage: int, properties: int, ) -> tuple[Any, Any]: """Create a Vulkan buffer + memory. Returns (buffer, memory).""" from ..gpu.memory import create_buffer return create_buffer(self.device, self.physical_device, size, usage, properties)
[docs] def create_image( self, width: int, height: int, fmt: int, usage: int, ) -> tuple[Any, Any]: """Create a Vulkan image + memory. Returns (image, memory).""" from ..gpu.memory import create_image return create_image(self.device, self.physical_device, width, height, fmt, usage)
[docs] def create_sampler(self) -> Any: """Create a default linear sampler.""" from ..gpu.memory import create_sampler return create_sampler(self.device)
[docs] def load_shader(self, filename: str) -> Any: """Compile a shader from the engine's shader directory and create a module.""" from ..gpu.pipeline import create_shader_module from ..materials.shader_compiler import compile_shader spv = compile_shader(self.shader_dir / filename) return create_shader_module(self.device, spv)
[docs] def upload_image_data( self, pixels: Any, width: int, height: int, fmt: int, ) -> tuple[Any, Any]: """Upload pixel data to a GPU image. Returns (image, memory).""" from ..gpu.memory import upload_image_data return upload_image_data( self.device, self.physical_device, self.graphics_queue, self.command_pool, pixels, width, height, fmt, )
[docs] def transition_image_layout( self, image: Any, old_layout: int, new_layout: int, ) -> None: """Transition an image between layouts (setup-time only).""" from ..gpu.memory import transition_image_layout transition_image_layout( self.device, self.graphics_queue, self.command_pool, image, old_layout, new_layout, )
[docs] def upload_numpy(self, memory: Any, data: Any) -> None: """Upload numpy array data to mapped GPU memory.""" from ..gpu.memory import upload_numpy upload_numpy(self.device, memory, data)