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}