// SPDX-License-Identifier: AGPL-3.0-only //! Snapshot types describing what the renderer submitted and what device it submitted to. use crate::renderer::RenderMode; /// The projection parameters used to build this frame's perspective matrix. #[derive(Copy, Clone, Debug, PartialEq)] pub struct ProjectionInfo { /// Vertical field of view, in radians. pub fov_y_radians: f32, /// Width-to-height ratio of the render target, derived from the swapchain extent. pub aspect: f32, /// Distance to the near clip plane, in blocks. pub near: f32, /// Distance to the far clip plane, in blocks. pub far: f32, } /// Description of the swapchain currently backing presentation. #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct SwapchainInfo { /// Number of images the swapchain was created with. pub image_count: u32, /// Width of the swapchain images, in pixels. pub width: u32, /// Height of the swapchain images, in pixels. pub height: u32, /// Presentation mode the swapchain was created with, rendered as its Vulkan enum name. pub present_mode: &'static str, } /// What the renderer submitted for one frame, plus the cumulative frame counters. /// /// Populated at the end of every successful [`Renderer::draw_frame`](crate::Renderer::draw_frame) and retained until the next frame replaces it, so a reader running on a slower cadence than the render loop always observes a complete, self-consistent frame rather than a partially-updated one. #[derive(Copy, Clone, Debug, PartialEq)] pub struct RenderStats { /// Total chunk meshes currently uploaded to the GPU, visible or not. pub uploaded_meshes: usize, /// Meshes that survived frustum culling and were submitted this frame. pub visible_meshes: usize, /// Meshes rejected by frustum culling this frame. pub culled_meshes: usize, /// Indexed draw calls recorded this frame: one per visible mesh per raster pass. pub draw_calls: usize, /// Triangles submitted this frame, counted across every pass. pub triangles: u64, /// Vertices referenced by the submitted meshes, counted across every pass. pub vertices: u64, /// Bytes of vertex buffer held by every uploaded mesh, visible or not. pub vertex_bytes: u64, /// Bytes of index buffer held by every uploaded mesh, visible or not. pub index_bytes: u64, /// The render mode in force this frame, which determines the pass list and therefore the draw-call multiplier. pub render_mode: RenderMode, /// Projection parameters used to build this frame's matrix. pub projection: ProjectionInfo, /// The swapchain backing presentation at the end of this frame. pub swapchain: SwapchainInfo, /// Frames presented since renderer initialisation. pub frames_presented: u64, /// Frames abandoned before submission because the swapchain reported itself out of date, typically during a window resize. pub frames_skipped: u64, } impl RenderStats { /// Returns the fraction of uploaded meshes rejected by frustum culling this frame, in percent. /// /// Returns zero when nothing was uploaded, since no meshes means no meshes were culled rather than an undefined ratio. #[must_use] pub fn cull_ratio_percent(&self) -> f32 { let considered = self.visible_meshes + self.culled_meshes; if considered == 0 { return 0.0; } // Mesh counts are bounded by the resident chunk set (thousands), far inside f32's exact-integer range. #[expect( clippy::cast_precision_loss, reason = "mesh counts stay well within f32's exact-integer range" )] { self.culled_meshes as f32 / considered as f32 * 100.0 } } } /// Immutable description of the physical device the renderer selected. /// /// Queried once at initialisation: every field is a property of the device or driver and cannot change for the lifetime of the renderer. Live memory figures are not part of this and are read separately through [`MemoryUsage`]. #[derive(Clone, Debug, PartialEq, Eq)] pub struct GpuInfo { /// Marketing name the driver reports for the device. pub device_name: String, /// Device class: discrete, integrated, virtual, CPU, or other. pub device_type: &'static str, /// PCI vendor identifier, as reported by the driver. pub vendor_id: u32, /// Vendor-assigned device identifier. pub device_id: u32, /// Driver version, decoded with the vendor's own packing scheme where it differs from the Vulkan convention. pub driver_version: String, /// Vulkan API version the device supports, as `major.minor.patch`. pub api_version: String, /// Total capacity of every heap flagged `DEVICE_LOCAL`, in bytes. This is dedicated video memory on a discrete device and a share of system memory on an integrated one. pub vram_total_bytes: u64, /// Whether `VK_EXT_memory_budget` was available and enabled, and therefore whether [`MemoryUsage`] can report driver-side figures. pub memory_budget_supported: bool, } /// Live memory figures, read on demand rather than cached. /// /// Two independent views: the driver's own accounting of the device-local heaps (available only where `VK_EXT_memory_budget` is supported) and the renderer's allocator, which sees only what this process suballocates. #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct MemoryUsage { /// Bytes the driver reports as currently in use across the device-local heaps, by every process. [`None`] where `VK_EXT_memory_budget` is unsupported. pub heap_usage_bytes: Option, /// Bytes the driver reports this process may use across the device-local heaps before it risks eviction. [`None`] where `VK_EXT_memory_budget` is unsupported. pub heap_budget_bytes: Option, /// Bytes currently handed out by the renderer's allocator as live suballocations. pub allocator_allocated_bytes: u64, /// Bytes the renderer's allocator holds in device memory blocks, including regions not yet suballocated. Always at least `allocator_allocated_bytes`; the difference is allocator slack. pub allocator_capacity_bytes: u64, } /// PCI vendor identifier for NVIDIA, whose driver packs `driver_version` differently from the Vulkan convention. const VENDOR_NVIDIA: u32 = 0x10DE; /// PCI vendor identifier for Intel, whose Windows driver packs `driver_version` differently from the Vulkan convention. const VENDOR_INTEL: u32 = 0x8086; /// Decodes a `VkPhysicalDeviceProperties::driverVersion` into a human-readable string. /// /// The field is documented as vendor-specific, and two vendors deviate from the `VK_MAKE_VERSION` packing the rest follow. NVIDIA uses a four-component 10/8/8/6-bit layout. Intel's Windows driver uses a 14/18-bit split; its Linux (Mesa) driver follows the Vulkan convention, so the deviation is applied only on Windows. Every other vendor is decoded as major/minor/patch. #[must_use] pub fn decode_driver_version(vendor_id: u32, version: u32) -> String { if vendor_id == VENDOR_NVIDIA { return format!( "{}.{}.{}.{}", (version >> 22) & 0x3ff, (version >> 14) & 0x0ff, (version >> 6) & 0x0ff, version & 0x3f ); } if vendor_id == VENDOR_INTEL && cfg!(windows) { return format!("{}.{}", version >> 14, version & 0x3fff); } format!( "{}.{}.{}", version >> 22, (version >> 12) & 0x3ff, version & 0xfff ) } #[cfg(test)] #[path = "tests/stats.rs"] mod tests;