1use bitflags::bitflags;
2use librashader_common::map::{FastHashMap, ShortString};
3use std::fmt::{Display, Formatter};
4use std::str::FromStr;
5
6pub const MAX_BINDINGS_COUNT: u32 = 16;
8pub const MAX_PUSH_BUFFER_SIZE: u32 = 128;
10
11#[derive(Debug, Ord, PartialOrd, Eq, PartialEq, Copy, Clone, Hash)]
13#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
14pub enum UniformType {
15 Mat4,
17 Vec4,
19 Unsigned,
21 Signed,
23 Float,
25}
26
27#[derive(Debug, Ord, PartialOrd, Eq, PartialEq, Copy, Clone, Hash)]
30#[repr(i32)]
31#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
32pub enum UniqueSemantics {
33 MVP = 0,
36 Output = 1,
39 FinalViewport = 2,
42 FrameCount = 3,
45 FrameDirection = 4,
48 FrameTimeDelta = 5,
51 OriginalFPS = 6,
54 Rotation = 7,
57 OriginalAspect = 8,
60 OriginalAspectRotated = 9,
62 TotalSubFrames = 10,
64 CurrentSubFrame = 11,
66 FloatParameter = 12,
69}
70
71impl UniqueSemantics {
72 pub const fn semantics(self) -> Semantic<UniqueSemantics, ()> {
74 Semantic {
75 semantics: self,
76 index: (),
77 }
78 }
79
80 pub const fn binding_type(&self) -> UniformType {
82 match self {
83 UniqueSemantics::MVP => UniformType::Mat4,
84 UniqueSemantics::Output => UniformType::Vec4,
85 UniqueSemantics::FinalViewport => UniformType::Vec4,
86 UniqueSemantics::FrameCount => UniformType::Unsigned,
87 UniqueSemantics::FrameDirection => UniformType::Signed,
88 UniqueSemantics::Rotation => UniformType::Unsigned,
89 UniqueSemantics::TotalSubFrames => UniformType::Unsigned,
90 UniqueSemantics::CurrentSubFrame => UniformType::Unsigned,
91 UniqueSemantics::FloatParameter => UniformType::Float,
92 UniqueSemantics::FrameTimeDelta => UniformType::Unsigned,
93 UniqueSemantics::OriginalFPS => UniformType::Float,
94 UniqueSemantics::OriginalAspect => UniformType::Float,
95 UniqueSemantics::OriginalAspectRotated => UniformType::Float,
96 }
97 }
98
99 pub const fn as_str(&self) -> &'static str {
101 match self {
102 UniqueSemantics::MVP => "MVP",
103 UniqueSemantics::Output => "Output",
104 UniqueSemantics::FinalViewport => "FinalViewport",
105 UniqueSemantics::FrameCount => "FrameCount",
106 UniqueSemantics::FrameDirection => "FrameDirection",
107 UniqueSemantics::Rotation => "Rotation",
108 UniqueSemantics::TotalSubFrames => "TotalSubFrames",
109 UniqueSemantics::CurrentSubFrame => "CurrentSubFrame",
110 UniqueSemantics::FloatParameter => "FloatParameter",
111 UniqueSemantics::FrameTimeDelta => "FrameTimeDelta",
112 UniqueSemantics::OriginalFPS => "OriginalFPS",
113 UniqueSemantics::OriginalAspect => "OriginalAspect",
114 UniqueSemantics::OriginalAspectRotated => "OriginalAspectRotated",
115 }
116 }
117}
118
119impl Display for UniqueSemantics {
120 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
121 write!(f, "{}", self.as_str())
122 }
123}
124
125#[derive(Debug, Ord, PartialOrd, Eq, PartialEq, Copy, Clone, Hash)]
129#[repr(i32)]
130#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
131pub enum TextureSemantics {
132 Original = 0,
134 Source = 1,
136 OriginalHistory = 2,
138 PassOutput = 3,
140 PassFeedback = 4,
142 User = 5,
144}
145
146impl TextureSemantics {
147 pub(crate) const TEXTURE_SEMANTICS: [TextureSemantics; 6] = [
148 TextureSemantics::Source,
149 TextureSemantics::OriginalHistory,
153 TextureSemantics::Original,
154 TextureSemantics::PassOutput,
155 TextureSemantics::PassFeedback,
156 TextureSemantics::User,
157 ];
158
159 pub fn size_uniform_name(&self) -> &'static str {
161 match self {
162 TextureSemantics::Original => "OriginalSize",
163 TextureSemantics::Source => "SourceSize",
164 TextureSemantics::OriginalHistory => "OriginalHistorySize",
165 TextureSemantics::PassOutput => "PassOutputSize",
166 TextureSemantics::PassFeedback => "PassFeedbackSize",
167 TextureSemantics::User => "UserSize",
168 }
169 }
170
171 pub fn texture_name(&self) -> &'static str {
173 match self {
174 TextureSemantics::Original => "Original",
175 TextureSemantics::Source => "Source",
176 TextureSemantics::OriginalHistory => "OriginalHistory",
177 TextureSemantics::PassOutput => "PassOutput",
178 TextureSemantics::PassFeedback => "PassFeedback",
179 TextureSemantics::User => "User",
180 }
181 }
182
183 pub fn is_indexed(&self) -> bool {
187 !matches!(self, TextureSemantics::Original | TextureSemantics::Source)
188 }
189
190 pub const fn semantics(self, index: usize) -> Semantic<TextureSemantics> {
192 Semantic {
193 semantics: self,
194 index,
195 }
196 }
197}
198
199pub(crate) struct TypeInfo {
200 pub size: u32,
201 pub columns: u32,
202}
203
204pub(crate) trait ValidateTypeSemantics<T> {
205 fn validate_type(&self, ty: &T) -> Option<TypeInfo>;
206}
207
208#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
210pub struct Semantic<T, I = usize> {
211 pub semantics: T,
213 pub index: I,
215}
216
217bitflags! {
218 #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone, Copy)]
220 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
221 #[cfg_attr(feature = "serde", serde(transparent))]
222 pub struct BindingStage: u8 {
223 const NONE = 0b00000000;
224 const VERTEX = 0b00000001;
225 const FRAGMENT = 0b00000010;
226 }
227}
228
229#[derive(Clone, Debug)]
231#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
232pub struct BufferReflection<T> {
233 pub binding: T,
235 pub size: u32,
237 pub stage_mask: BindingStage,
239}
240
241#[derive(Debug, Copy, Clone, PartialEq, Eq)]
245#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
246pub struct MemberOffset {
247 pub ubo: Option<usize>,
249 pub push: Option<usize>,
251}
252
253#[derive(Debug, Clone, Copy, PartialEq, Eq)]
254#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
255pub enum UniformMemberBlock {
257 Ubo,
259 PushConstant,
261}
262
263impl UniformMemberBlock {
264 pub const TYPES: [UniformMemberBlock; 2] =
266 [UniformMemberBlock::Ubo, UniformMemberBlock::PushConstant];
267}
268
269impl MemberOffset {
270 pub(crate) fn new(off: usize, ty: UniformMemberBlock) -> Self {
271 match ty {
272 UniformMemberBlock::Ubo => MemberOffset {
273 ubo: Some(off),
274 push: None,
275 },
276 UniformMemberBlock::PushConstant => MemberOffset {
277 ubo: None,
278 push: Some(off),
279 },
280 }
281 }
282
283 pub fn offset(&self, ty: UniformMemberBlock) -> Option<usize> {
284 match ty {
285 UniformMemberBlock::Ubo => self.ubo,
286 UniformMemberBlock::PushConstant => self.push,
287 }
288 }
289
290 pub(crate) fn offset_mut(&mut self, ty: UniformMemberBlock) -> &mut Option<usize> {
291 match ty {
292 UniformMemberBlock::Ubo => &mut self.ubo,
293 UniformMemberBlock::PushConstant => &mut self.push,
294 }
295 }
296}
297
298#[derive(Clone, Debug)]
300#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
301pub struct VariableMeta {
302 pub offset: MemberOffset,
304 pub size: u32,
306 pub id: ShortString,
308}
309
310#[derive(Clone, Debug)]
312#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
313pub struct TextureSizeMeta {
314 pub offset: MemberOffset,
317 pub stage_mask: BindingStage,
319 pub id: ShortString,
321}
322
323#[derive(Clone, Debug)]
325#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
326pub struct TextureBinding {
327 pub binding: u32,
329}
330
331#[derive(Clone, Debug)]
333#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
334pub struct ShaderReflection {
335 pub ubo: Option<BufferReflection<u32>>,
337 pub push_constant: Option<BufferReflection<Option<u32>>>,
339 pub meta: BindingMeta,
341}
342
343pub trait UniformMeta {
345 fn offset(&self) -> MemberOffset;
347 fn id(&self) -> &str;
349}
350
351impl UniformMeta for VariableMeta {
352 fn offset(&self) -> MemberOffset {
353 self.offset
354 }
355
356 fn id(&self) -> &str {
357 &self.id
358 }
359}
360
361impl UniformMeta for TextureSizeMeta {
362 fn offset(&self) -> MemberOffset {
363 self.offset
364 }
365 fn id(&self) -> &str {
366 &self.id
367 }
368}
369
370pub trait TextureSemanticMap {
372 fn texture_semantic(&self, name: &str) -> Option<Semantic<TextureSemantics>>;
374}
375
376impl TextureSemanticMap for FastHashMap<ShortString, UniformSemantic> {
377 fn texture_semantic(&self, name: &str) -> Option<Semantic<TextureSemantics>> {
378 match self.get(name) {
379 None => {
380 if let Some(semantics) = TextureSemantics::TEXTURE_SEMANTICS
381 .iter()
382 .find(|f| name.starts_with(f.size_uniform_name()))
383 {
384 if semantics.is_indexed() {
385 let index = &name[semantics.size_uniform_name().len()..];
386 let Ok(index) = usize::from_str(index) else {
387 return None;
388 };
389 return Some(Semantic {
390 semantics: *semantics,
391 index,
392 });
393 } else if name == semantics.size_uniform_name() {
394 return Some(Semantic {
395 semantics: *semantics,
396 index: 0,
397 });
398 }
399 }
400 None
401 }
402 Some(UniformSemantic::Unique(_)) => None,
403 Some(UniformSemantic::Texture(texture)) => Some(*texture),
404 }
405 }
406}
407
408impl TextureSemanticMap for FastHashMap<ShortString, Semantic<TextureSemantics>> {
409 fn texture_semantic(&self, name: &str) -> Option<Semantic<TextureSemantics>> {
410 match self.get(name) {
411 None => {
412 if let Some(semantics) = TextureSemantics::TEXTURE_SEMANTICS
413 .iter()
414 .find(|f| name.starts_with(f.texture_name()))
415 {
416 if semantics.is_indexed() {
417 let index = &name[semantics.texture_name().len()..];
418 let Ok(index) = usize::from_str(index) else {
419 return None;
420 };
421 return Some(Semantic {
422 semantics: *semantics,
423 index,
424 });
425 } else if name == semantics.texture_name() {
426 return Some(Semantic {
427 semantics: *semantics,
428 index: 0,
429 });
430 }
431 }
432 None
433 }
434 Some(texture) => Some(*texture),
435 }
436 }
437}
438
439pub trait UniqueSemanticMap {
441 fn unique_semantic(&self, name: &str) -> Option<Semantic<UniqueSemantics, ()>>;
443}
444
445impl UniqueSemanticMap for FastHashMap<ShortString, UniformSemantic> {
446 fn unique_semantic(&self, name: &str) -> Option<Semantic<UniqueSemantics, ()>> {
447 match self.get(name) {
448 None => match name {
450 "MVP" => Some(Semantic {
451 semantics: UniqueSemantics::MVP,
452 index: (),
453 }),
454 "OutputSize" => Some(Semantic {
455 semantics: UniqueSemantics::Output,
456 index: (),
457 }),
458 "FinalViewportSize" => Some(Semantic {
459 semantics: UniqueSemantics::FinalViewport,
460 index: (),
461 }),
462 "FrameCount" => Some(Semantic {
463 semantics: UniqueSemantics::FrameCount,
464 index: (),
465 }),
466 "FrameDirection" => Some(Semantic {
467 semantics: UniqueSemantics::FrameDirection,
468 index: (),
469 }),
470 "Rotation" => Some(Semantic {
471 semantics: UniqueSemantics::Rotation,
472 index: (),
473 }),
474 "TotalSubFrames" => Some(Semantic {
475 semantics: UniqueSemantics::TotalSubFrames,
476 index: (),
477 }),
478 "CurrentSubFrame" => Some(Semantic {
479 semantics: UniqueSemantics::CurrentSubFrame,
480 index: (),
481 }),
482 "OriginalAspect" => Some(Semantic {
483 semantics: UniqueSemantics::OriginalAspect,
484 index: (),
485 }),
486 "OriginalAspectRotated" => Some(Semantic {
487 semantics: UniqueSemantics::OriginalAspectRotated,
488 index: (),
489 }),
490 "OriginalFPS" => Some(Semantic {
491 semantics: UniqueSemantics::OriginalFPS,
492 index: (),
493 }),
494 "FrameTimeDelta" => Some(Semantic {
495 semantics: UniqueSemantics::FrameTimeDelta,
496 index: (),
497 }),
498 _ => None,
499 },
500 Some(UniformSemantic::Unique(variable)) => Some(*variable),
501 Some(UniformSemantic::Texture(_)) => None,
502 }
503 }
504}
505
506#[derive(Debug, Clone)]
508#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
509pub enum UniformSemantic {
510 Unique(Semantic<UniqueSemantics, ()>),
512 Texture(Semantic<TextureSemantics>),
514}
515
516#[derive(Debug, Clone)]
518#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
519pub struct ShaderSemantics {
520 pub uniform_semantics: FastHashMap<ShortString, UniformSemantic>,
522 pub texture_semantics: FastHashMap<ShortString, Semantic<TextureSemantics>>,
524}
525
526#[derive(Debug, Clone, Eq, Hash, PartialEq)]
531#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
532pub enum UniformBinding {
533 Parameter(ShortString),
535 SemanticVariable(UniqueSemantics),
537 TextureSize(Semantic<TextureSemantics>),
539}
540
541impl From<UniqueSemantics> for UniformBinding {
542 fn from(value: UniqueSemantics) -> Self {
543 UniformBinding::SemanticVariable(value)
544 }
545}
546
547impl From<Semantic<TextureSemantics>> for UniformBinding {
548 fn from(value: Semantic<TextureSemantics>) -> Self {
549 UniformBinding::TextureSize(value)
550 }
551}
552
553#[derive(Debug, Default, Clone)]
555#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
556pub struct BindingMeta {
557 #[cfg_attr(feature = "serde", serde(rename = "param"))]
558 pub parameter_meta: FastHashMap<ShortString, VariableMeta>,
560 #[cfg_attr(feature = "serde", serde(rename = "unique"))]
561 pub unique_meta: FastHashMap<UniqueSemantics, VariableMeta>,
563 #[cfg_attr(feature = "serde", serde(rename = "texture"))]
564 pub texture_meta: FastHashMap<Semantic<TextureSemantics>, TextureBinding>,
566 #[cfg_attr(feature = "serde", serde(rename = "texture_size"))]
567 pub texture_size_meta: FastHashMap<Semantic<TextureSemantics>, TextureSizeMeta>,
569}
570
571#[cfg(feature = "serde")]
572mod serde_impl {
573 use super::*;
574 use serde::de::{Deserialize, Visitor};
575 use serde::ser::Serialize;
576 use serde::{Deserializer, Serializer};
577
578 struct TextureSemanticVisitor;
579
580 impl<'de> Visitor<'de> for TextureSemanticVisitor {
581 type Value = Semantic<TextureSemantics>;
582
583 fn expecting(&self, formatter: &mut Formatter) -> std::fmt::Result {
584 formatter.write_str("a string of the form (Semantic)N?")
585 }
586
587 fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
588 where
589 E: serde::de::Error,
590 {
591 match v {
592 "Original" => Ok(TextureSemantics::Original.semantics(0)),
593 "Source" => Ok(TextureSemantics::Source.semantics(0)),
594 other => {
595 let Some(index) = other.find(|c: char| c.is_digit(10)) else {
596 return Err(E::custom(format!(
597 "expected index for indexed texture semantic {v}"
598 )));
599 };
600
601 let (semantic, index) = other.split_at(index);
602 let Ok(index) = index.parse::<usize>() else {
603 return Err(E::custom(format!(
604 "could not parse index {index} of texture semantic {v}"
605 )));
606 };
607
608 match semantic {
609 "OriginalHistory" => Ok(TextureSemantics::OriginalHistory.semantics(index)),
610 "PassOutput" => Ok(TextureSemantics::PassOutput.semantics(index)),
611 "PassFeedback" => Ok(TextureSemantics::PassFeedback.semantics(index)),
612 _ => Ok(TextureSemantics::User.semantics(index)),
614 }
615 }
616 }
617 }
618 }
619 impl<'de> Deserialize<'de> for Semantic<TextureSemantics> {
620 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
621 where
622 D: Deserializer<'de>,
623 {
624 deserializer.deserialize_str(TextureSemanticVisitor)
625 }
626 }
627
628 impl Serialize for Semantic<TextureSemantics> {
629 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
630 where
631 S: Serializer,
632 {
633 if self.semantics.is_indexed() {
634 serializer.serialize_str(&format!(
635 "{}{}",
636 self.semantics.texture_name(),
637 self.index
638 ))
639 } else {
640 serializer.serialize_str(&format!("{}", self.semantics.texture_name()))
641 }
642 }
643 }
644
645 struct UniqueSemanticsVisitor;
646 impl<'de> Visitor<'de> for UniqueSemanticsVisitor {
647 type Value = Semantic<UniqueSemantics, ()>;
648
649 fn expecting(&self, formatter: &mut Formatter) -> std::fmt::Result {
650 formatter.write_str("a valid uniform semantic name")
651 }
652
653 fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
654 where
655 E: serde::de::Error,
656 {
657 Ok(match v {
658 "MVP" => Semantic {
659 semantics: UniqueSemantics::MVP,
660 index: (),
661 },
662 "OutputSize" => Semantic {
663 semantics: UniqueSemantics::Output,
664 index: (),
665 },
666 "FinalViewportSize" => Semantic {
667 semantics: UniqueSemantics::FinalViewport,
668 index: (),
669 },
670 "FrameCount" => Semantic {
671 semantics: UniqueSemantics::FrameCount,
672 index: (),
673 },
674 "FrameDirection" => Semantic {
675 semantics: UniqueSemantics::FrameDirection,
676 index: (),
677 },
678 "Rotation" => Semantic {
679 semantics: UniqueSemantics::Rotation,
680 index: (),
681 },
682 "TotalSubFrames" => Semantic {
683 semantics: UniqueSemantics::TotalSubFrames,
684 index: (),
685 },
686 "CurrentSubFrame" => Semantic {
687 semantics: UniqueSemantics::CurrentSubFrame,
688 index: (),
689 },
690 _ => return Err(E::custom(format!("unknown unique semantic {v}"))),
691 })
692 }
693 }
694
695 impl Serialize for Semantic<UniqueSemantics, ()> {
696 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
697 where
698 S: Serializer,
699 {
700 serializer.serialize_str(self.semantics.as_str())
701 }
702 }
703
704 impl<'de> Deserialize<'de> for Semantic<UniqueSemantics, ()> {
705 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
706 where
707 D: Deserializer<'de>,
708 {
709 deserializer.deserialize_str(UniqueSemanticsVisitor)
710 }
711 }
712}