1use crate::{GpuSlot, StreamElement, TypedSlot};
2
3const DOMAIN_SHIFT: u32 = 24;
4const LOCAL_MASK: u32 = (1 << DOMAIN_SHIFT) - 1;
5
6#[derive(Clone, Copy, PartialEq, Eq)]
7pub struct ResourceId(u32);
8
9impl ResourceId {
10 pub const fn new(domain: u32, local: u32) -> Self {
11 assert!(domain < (1 << (32 - DOMAIN_SHIFT)));
12 assert!(local < (1 << DOMAIN_SHIFT));
13 Self((domain << DOMAIN_SHIFT) | local)
14 }
15
16 pub const fn domain(self) -> u32 {
17 self.0 >> DOMAIN_SHIFT
18 }
19
20 pub const fn local(self) -> u32 {
21 self.0 & LOCAL_MASK
22 }
23}
24
25#[derive(Clone, Copy)]
26pub enum SlotRef {
27 Whole {
28 resource: ResourceId,
29 element: StreamElement,
30 },
31 Range {
32 resource: ResourceId,
33 offset: u64,
34 size: u64,
35 element: StreamElement,
36 },
37}
38
39impl SlotRef {
40 pub const fn whole(resource: ResourceId, element: StreamElement) -> Self {
41 Self::Whole { resource, element }
42 }
43
44 pub const fn range(
45 resource: ResourceId,
46 offset: u64,
47 size: u64,
48 element: StreamElement,
49 ) -> Self {
50 Self::Range {
51 resource,
52 offset,
53 size,
54 element,
55 }
56 }
57
58 pub const fn element(self) -> StreamElement {
59 match self {
60 Self::Whole { element, .. } | Self::Range { element, .. } => element,
61 }
62 }
63
64 pub fn resolve<R: Resources>(self, resources: &R) -> TypedSlot<'_> {
65 match self {
66 Self::Whole { resource, .. } => {
67 TypedSlot::new(resources.whole(resource), self.element())
68 }
69 Self::Range {
70 resource,
71 offset,
72 size,
73 ..
74 } => TypedSlot::new(resources.range(resource, offset, size), self.element()),
75 }
76 }
77}
78
79pub trait Resources {
80 fn generation(&self) -> u64;
81
82 fn slots(&self, resource: ResourceId) -> u32;
83
84 fn whole(&self, resource: ResourceId) -> GpuSlot<'_>;
85
86 fn range(&self, resource: ResourceId, offset: u64, size: u64) -> GpuSlot<'_>;
87}