1use fnv::FnvHashMap as HashMap;
3
4use crate::{
5 error::{anyhow, Result},
6 ty::{AccessType, Type},
7 var::{DescriptorBinding, InterfaceLocation},
8};
9
10pub use spirv::Decoration;
11
12type VariableId = u32;
13type InstrId = u32;
14
15#[derive(Clone, Copy, PartialEq, Eq, Hash)]
16struct DecorationKey {
17 pub id: InstrId,
18 pub member_idx: Option<u32>,
19 pub deco: Decoration,
20}
21impl DecorationKey {
22 pub fn new(id: InstrId, deco: Decoration) -> Self {
23 Self {
24 id,
25 member_idx: None,
26 deco,
27 }
28 }
29 pub fn new_member(id: InstrId, member_idx: u32, deco: Decoration) -> Self {
30 Self {
31 id,
32 member_idx: Some(member_idx),
33 deco,
34 }
35 }
36}
37
38#[derive(Default)]
39pub struct DecorationRegistry<'a> {
40 deco_map: HashMap<DecorationKey, &'a [u32]>,
41}
42impl<'a> DecorationRegistry<'a> {
43 fn set_impl(&mut self, key: DecorationKey, operands: &'a [u32]) -> Result<()> {
44 use std::collections::hash_map::Entry;
45 match self.deco_map.entry(key) {
46 Entry::Vacant(entry) => {
47 entry.insert(operands);
48 Ok(())
49 }
50 Entry::Occupied(_) => Err(anyhow!("duplicate decoration at id {}", key.id)),
51 }
52 }
53 fn get_impl(&self, key: DecorationKey) -> Result<&'a [u32]> {
54 self.deco_map
55 .get(&key)
56 .copied()
57 .ok_or(anyhow!("missing decoration at id {}", key.id))
58 }
59
60 pub fn set(&mut self, id: InstrId, deco: Decoration, operands: &'a [u32]) -> Result<()> {
61 self.set_impl(DecorationKey::new(id, deco), operands)
62 }
63 pub fn set_member(
64 &mut self,
65 id: InstrId,
66 member_idx: u32,
67 deco: Decoration,
68 operands: &'a [u32],
69 ) -> Result<()> {
70 self.set_impl(DecorationKey::new_member(id, member_idx, deco), operands)
71 }
72 pub fn get(&self, id: InstrId, deco: Decoration) -> Result<&'a [u32]> {
73 self.get_impl(DecorationKey::new(id, deco))
74 }
75 pub fn get_member(&self, id: InstrId, member_idx: u32, deco: Decoration) -> Result<&'a [u32]> {
76 self.get_impl(DecorationKey::new_member(id, member_idx, deco))
77 }
78
79 pub fn get_u32(&self, id: InstrId, deco: Decoration) -> Result<u32> {
80 self.get(id, deco)
81 .and_then(|x| {
82 x.get(0).ok_or(anyhow!(
83 "expected a single operand for decoration {:?} at id {}",
84 deco,
85 id
86 ))
87 })
88 .copied()
89 }
90 pub fn get_member_u32(&self, id: InstrId, member_idx: u32, deco: Decoration) -> Result<u32> {
91 self.get_member(id, member_idx, deco)
92 .and_then(|x| {
93 x.get(0).ok_or(anyhow!(
94 "expected a single operand for member decoration {:?} at id {} for member {}",
95 deco,
96 id,
97 member_idx
98 ))
99 })
100 .copied()
101 }
102
103 pub fn contains(&self, id: InstrId, deco: Decoration) -> bool {
104 self.deco_map.contains_key(&DecorationKey::new(id, deco))
105 }
106 pub fn contains_member(&self, id: InstrId, member_idx: u32, deco: Decoration) -> bool {
107 self.deco_map
108 .contains_key(&DecorationKey::new_member(id, member_idx, deco))
109 }
110
111 pub fn get_all(&self, deco: Decoration) -> impl Iterator<Item = (InstrId, &[u32])> {
112 self.deco_map
113 .iter()
114 .filter(move |(key, _)| key.deco == deco)
115 .map(|(key, value)| (key.id, *value))
116 }
117
118 pub fn get_var_location(&self, var_id: VariableId) -> Result<InterfaceLocation> {
120 let comp = self.get_u32(var_id, Decoration::Component).unwrap_or(0);
121 self.get_u32(var_id, Decoration::Location)
122 .map(|loc| InterfaceLocation::new(loc, comp))
123 }
124 pub fn get_var_desc_bind(&self, var_id: VariableId) -> Result<DescriptorBinding> {
126 let desc_set = self.get_u32(var_id, Decoration::DescriptorSet).unwrap_or(0);
127 self.get_u32(var_id, Decoration::Binding)
128 .map(|bind_point| DescriptorBinding::new(desc_set, bind_point))
129 }
130 pub fn get_var_desc_bind_or_default(&self, var_id: VariableId) -> DescriptorBinding {
133 self.get_var_desc_bind(var_id)
134 .unwrap_or(DescriptorBinding::new(0, 0))
135 }
136 pub fn get_desc_access_ty(&self, id: InstrId, ty: &Type) -> Option<AccessType> {
138 self.get_access_ty_from_deco(id).and_then(|x| {
139 if x == AccessType::ReadWrite {
141 match ty.access_ty() {
142 Some(x) => Some(x),
143 None => Some(AccessType::ReadWrite),
144 }
145 } else {
146 Some(x)
147 }
148 })
149 }
150 pub fn get_access_ty_from_deco(&self, id: InstrId) -> Option<AccessType> {
151 let write_only = self.contains(id, Decoration::NonReadable);
152 let read_only = self.contains(id, Decoration::NonWritable);
153 match (write_only, read_only) {
154 (true, true) => None,
155 (true, false) => Some(AccessType::WriteOnly),
156 (false, true) => Some(AccessType::ReadOnly),
157 (false, false) => Some(AccessType::ReadWrite),
158 }
159 }
160 pub fn get_member_access_ty_from_deco(
161 &self,
162 id: InstrId,
163 member_idx: u32,
164 ) -> Option<AccessType> {
165 let write_only = self.contains_member(id, member_idx, Decoration::NonReadable);
166 let read_only = self.contains_member(id, member_idx, Decoration::NonWritable);
167 match (write_only, read_only) {
168 (true, true) => None,
169 (true, false) => Some(AccessType::WriteOnly),
170 (false, true) => Some(AccessType::ReadOnly),
171 (false, false) => Some(AccessType::ReadWrite),
172 }
173 }
174
175 pub fn get_var_input_attm_idx(&self, var_id: VariableId) -> Result<u32> {
177 self.get_u32(var_id, Decoration::InputAttachmentIndex)
178 }
179}
180
181#[derive(Clone, PartialEq, Eq, Hash)]
182pub struct NameKey {
183 pub id: InstrId,
184 pub member_idx: Option<u32>,
185}
186#[derive(Default)]
187pub struct NameRegistry<'a> {
188 name_map: HashMap<NameKey, &'a str>,
189}
190impl<'a> NameRegistry<'a> {
191 pub fn set(&mut self, id: InstrId, name: &'a str) {
193 use std::collections::hash_map::Entry;
194 let key = NameKey {
195 id,
196 member_idx: None,
197 };
198 match self.name_map.entry(key) {
199 Entry::Vacant(entry) => {
200 entry.insert(name);
201 }
202 _ => {}
203 }
204 }
205 pub fn set_member(&mut self, id: InstrId, member_idx: u32, name: &'a str) {
206 use std::collections::hash_map::Entry;
207 let key = NameKey {
208 id,
209 member_idx: Some(member_idx),
210 };
211 match self.name_map.entry(key) {
212 Entry::Vacant(entry) => {
213 entry.insert(name);
214 }
215 _ => {}
216 }
217 }
218
219 pub fn get(&self, id: InstrId) -> Option<&'a str> {
220 self.name_map
221 .get(&NameKey {
222 id,
223 member_idx: None,
224 })
225 .copied()
226 }
227 pub fn get_member(&self, id: InstrId, member_idx: u32) -> Option<&'a str> {
228 self.name_map
229 .get(&NameKey {
230 id,
231 member_idx: Some(member_idx),
232 })
233 .copied()
234 }
235
236 pub fn iter(&self) -> impl Iterator<Item = (&NameKey, &&'a str)> {
237 self.name_map.iter()
238 }
239}