Skip to main content

appcore_render/
limits.rs

1// =============================================================================
2//        #######
3//     ###       ###     F: limits.rs
4//    ##   ## ##   ##    P: AppCore-Runtime
5//         ## ##
6//                       C: 2026/10/14 16:20:57 by dnettoRaw
7//    ##   ## ##   ##    U: 2026/10/15 10:24:40 by dnettoRaw
8//      ###########      S: 0.1.0-alpha.1
9// =============================================================================
10
11/// Controlled errors at rendering/resource admission boundaries.
12#[derive(Debug, Clone, Copy, PartialEq, Eq)]
13pub enum RenderError {
14    /// Outstanding owned scene snapshots reached their configured capacity.
15    SnapshotsPending,
16    /// A bounded CPU reservation could not be allocated.
17    CpuAllocationFailed,
18    /// Two presentation submissions are pending; caller must keep pumping.
19    FramesPending,
20    /// Surface needs explicit resize/recreation before further submission.
21    SurfaceUnavailable,
22    /// Renderer no longer accepts new operations.
23    RendererClosed,
24    /// Device rejected bounded target/pipeline allocation or validation.
25    GpuAllocationFailed,
26    /// Required native GPU adapter/device is unavailable or lost.
27    DeviceUnavailable,
28    /// Diagnostic capture could not map the submitted result.
29    CaptureFailed,
30    /// Diagnostic capture did not finish within its fixed deadline.
31    CaptureTimeout,
32    /// Dimensions or configured limits are outside the supported range.
33    InvalidLimits,
34    /// Managed bytes or slot capacity would exceed its declared budget.
35    BudgetExceeded,
36    /// A handle is stale or belongs to another arena.
37    InvalidResource,
38    /// A monotonically increasing identity cannot advance safely.
39    IdentityExhausted,
40}
41impl std::fmt::Display for RenderError {
42    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
43        write!(f, "{self:?}")
44    }
45}
46impl std::error::Error for RenderError {}
47
48/// Limits for managed resources; excludes driver and operating-system overhead.
49#[derive(Debug, Clone, Copy, PartialEq, Eq)]
50pub struct RenderLimits {
51    /// Maximum physical attachment width/height.
52    pub max_dimension: u32,
53    /// Total bytes admitted by a resource arena.
54    pub managed_bytes: u64,
55    /// Maximum live or retired resource slots.
56    pub resource_slots: u32,
57}
58impl Default for RenderLimits {
59    fn default() -> Self {
60        Self {
61            max_dimension: 4096,
62            managed_bytes: 128 * 1024 * 1024,
63            resource_slots: 512,
64        }
65    }
66}
67impl RenderLimits {
68    /// Validate configuration before allocating slots or GPU memory.
69    pub fn validate(self) -> Result<Self, RenderError> {
70        if self.max_dimension == 0
71            || self.max_dimension > 16384
72            || self.managed_bytes == 0
73            || self.resource_slots == 0
74            || self.resource_slots > 65536
75        {
76            return Err(RenderError::InvalidLimits);
77        }
78        Ok(self)
79    }
80    /// Account RGBA8 color and Depth32Float attachments before creation.
81    pub fn attachment_bytes(self, width: u32, height: u32) -> Result<u64, RenderError> {
82        self.validate()?;
83        if width == 0 || height == 0 || width > self.max_dimension || height > self.max_dimension {
84            return Err(RenderError::InvalidLimits);
85        }
86        let bytes = u64::from(width) * u64::from(height) * 8;
87        if bytes > self.managed_bytes {
88            return Err(RenderError::BudgetExceeded);
89        }
90        Ok(bytes)
91    }
92}