From a72a5930296c7e46a647ae796305d8cd27a85c71 Mon Sep 17 00:00:00 2001 From: chyyran Date: Thu, 26 Sep 2024 17:37:45 -0400 Subject: [PATCH] reflect: allow indexed and non-indexed semantics to be serialized and deserialized as strings --- Cargo.lock | 23 +-- librashader-reflect/src/reflect/semantics.rs | 170 ++++++++++++++++++- librashader-test/Cargo.toml | 1 - librashader-test/src/cli/main.rs | 24 ++- 4 files changed, 182 insertions(+), 36 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2bc2c0f..bb38fff 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -251,12 +251,6 @@ version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" -[[package]] -name = "base64" -version = "0.21.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" - [[package]] name = "bincode" version = "2.0.0-rc.3" @@ -687,7 +681,7 @@ dependencies = [ "lazy_static", "nom", "pathdiff", - "ron 0.7.1", + "ron", "rust-ini", "serde", "serde_json", @@ -1839,7 +1833,6 @@ dependencies = [ "objc2-metal", "parking_lot", "pollster", - "ron 0.8.1", "serde", "serde_json", "spq-spvasm", @@ -2735,23 +2728,11 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "88073939a61e5b7680558e6be56b419e208420c2adb92be54921fa6b72283f1a" dependencies = [ - "base64 0.13.1", + "base64", "bitflags 1.3.2", "serde", ] -[[package]] -name = "ron" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b91f7eff05f748767f183df4320a63d6936e9c6107d97c9e6bdd9784f4289c94" -dependencies = [ - "base64 0.21.7", - "bitflags 2.6.0", - "serde", - "serde_derive", -] - [[package]] name = "rspirv" version = "0.12.0+sdk-1.3.268.0" diff --git a/librashader-reflect/src/reflect/semantics.rs b/librashader-reflect/src/reflect/semantics.rs index af77fa9..0cb35c9 100644 --- a/librashader-reflect/src/reflect/semantics.rs +++ b/librashader-reflect/src/reflect/semantics.rs @@ -1,5 +1,6 @@ use bitflags::bitflags; use librashader_common::map::{FastHashMap, ShortString}; +use std::fmt::{Display, Formatter}; use std::str::FromStr; /// The maximum number of bindings allowed in a shader. @@ -79,6 +80,27 @@ impl UniqueSemantics { UniqueSemantics::FloatParameter => UniformType::Float, } } + + /// Get the name of the semantic as a string. + pub const fn as_str(&self) -> &'static str { + match self { + UniqueSemantics::MVP => "MVP", + UniqueSemantics::Output => "Output", + UniqueSemantics::FinalViewport => "FinalViewport", + UniqueSemantics::FrameCount => "FrameCount", + UniqueSemantics::FrameDirection => "FrameDirection", + UniqueSemantics::Rotation => "Rotation", + UniqueSemantics::TotalSubFrames => "TotalSubFrames", + UniqueSemantics::CurrentSubFrame => "CurrentSubFrame", + UniqueSemantics::FloatParameter => "FloatParameter", + } + } +} + +impl Display for UniqueSemantics { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.as_str()) + } } /// Texture semantics relate to input or output textures. @@ -166,7 +188,6 @@ pub(crate) trait ValidateTypeSemantics { /// A unit of unique or indexed semantic. #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Semantic { /// The semantics of this unit. pub semantics: T, @@ -498,12 +519,159 @@ impl From> for UniformBinding { #[derive(Debug, Default, Clone)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct BindingMeta { + #[cfg_attr(feature = "serde", serde(rename = "param"))] /// A map of parameter names to uniform binding metadata. pub parameter_meta: FastHashMap, + #[cfg_attr(feature = "serde", serde(rename = "unique"))] /// A map of unique semantics to uniform binding metadata. pub unique_meta: FastHashMap, + #[cfg_attr(feature = "serde", serde(rename = "texture"))] /// A map of texture semantics to texture binding points. pub texture_meta: FastHashMap, TextureBinding>, + #[cfg_attr(feature = "serde", serde(rename = "texture_size"))] /// A map of texture semantics to texture size uniform binding metadata. pub texture_size_meta: FastHashMap, TextureSizeMeta>, } + +#[cfg(feature = "serde")] +mod serde_impl { + use super::*; + use serde::de::{Deserialize, Visitor}; + use serde::ser::Serialize; + use serde::{Deserializer, Serializer}; + + struct TextureSemanticVisitor; + + impl<'de> Visitor<'de> for TextureSemanticVisitor { + type Value = Semantic; + + fn expecting(&self, formatter: &mut Formatter) -> std::fmt::Result { + formatter.write_str("a string of the form (Semantic)N?") + } + + fn visit_str(self, v: &str) -> Result + where + E: serde::de::Error, + { + match v { + "Original" => Ok(TextureSemantics::Original.semantics(0)), + "Source" => Ok(TextureSemantics::Source.semantics(0)), + other => { + let Some(index) = other.find(|c: char| c.is_digit(10)) else { + return Err(E::custom(format!( + "expected index for indexed texture semantic {v}" + ))); + }; + + let (semantic, index) = other.split_at(index); + let Ok(index) = index.parse::() else { + return Err(E::custom(format!( + "could not parse index {index} of texture semantic {v}" + ))); + }; + + match semantic { + "OriginalHistory" => Ok(TextureSemantics::OriginalHistory.semantics(index)), + "PassOutput" => Ok(TextureSemantics::PassOutput.semantics(index)), + "PassFeedback" => Ok(TextureSemantics::PassFeedback.semantics(index)), + // everything else (including "User") is a user semantic. + _ => Ok(TextureSemantics::User.semantics(index)), + } + } + } + } + } + impl<'de> Deserialize<'de> for Semantic { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_str(TextureSemanticVisitor) + } + } + + impl Serialize for Semantic { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + if self.semantics.is_indexed() { + serializer.serialize_str(&format!( + "{}{}", + self.semantics.texture_name(), + self.index + )) + } else { + serializer.serialize_str(&format!("{}", self.semantics.texture_name())) + } + } + } + + struct UniqueSemanticsVisitor; + impl<'de> Visitor<'de> for UniqueSemanticsVisitor { + type Value = Semantic; + + fn expecting(&self, formatter: &mut Formatter) -> std::fmt::Result { + formatter.write_str("a valid uniform semantic name") + } + + fn visit_str(self, v: &str) -> Result + where + E: serde::de::Error, + { + Ok(match v { + "MVP" => Semantic { + semantics: UniqueSemantics::MVP, + index: (), + }, + "OutputSize" => Semantic { + semantics: UniqueSemantics::Output, + index: (), + }, + "FinalViewportSize" => Semantic { + semantics: UniqueSemantics::FinalViewport, + index: (), + }, + "FrameCount" => Semantic { + semantics: UniqueSemantics::FrameCount, + index: (), + }, + "FrameDirection" => Semantic { + semantics: UniqueSemantics::FrameDirection, + index: (), + }, + "Rotation" => Semantic { + semantics: UniqueSemantics::Rotation, + index: (), + }, + "TotalSubFrames" => Semantic { + semantics: UniqueSemantics::TotalSubFrames, + index: (), + }, + "CurrentSubFrame" => Semantic { + semantics: UniqueSemantics::CurrentSubFrame, + index: (), + }, + _ => return Err(E::custom(format!("unknown unique semantic {v}"))), + }) + } + } + + impl Serialize for Semantic { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_str(self.semantics.as_str()) + } + } + + impl<'de> Deserialize<'de> for Semantic { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_str(UniqueSemanticsVisitor) + } + } +} diff --git a/librashader-test/Cargo.toml b/librashader-test/Cargo.toml index 778f9ce..7db361c 100644 --- a/librashader-test/Cargo.toml +++ b/librashader-test/Cargo.toml @@ -33,7 +33,6 @@ clap = { workspace = true } serde = "1.0" serde_json = "1.0" spq-spvasm = "0.1.4" -ron = "0.8.1" [features] default = ["full"] diff --git a/librashader-test/src/cli/main.rs b/librashader-test/src/cli/main.rs index 24973a5..e25a667 100644 --- a/librashader-test/src/cli/main.rs +++ b/librashader-test/src/cli/main.rs @@ -8,7 +8,6 @@ use librashader::reflect::naga::{Naga, NagaLoweringOptions}; use librashader::reflect::semantics::ShaderSemantics; use librashader::reflect::{CompileShader, FromCompilation, ReflectShader, SpirvCompilation}; use librashader_test::render::RenderTest; -use ron::ser::PrettyConfig; use std::path::{Path, PathBuf}; #[derive(Parser, Debug)] @@ -337,10 +336,11 @@ pub fn main() -> Result<(), anyhow::Error> { } } TranspileFormat::MSL => { - let mut compilation = >::from_compilation(compilation)?; + let mut compilation = + >::from_compilation(compilation)?; compilation.validate()?; let output = compilation.compile(Some(MslVersion::new(1, 2, 0)))?; @@ -350,10 +350,11 @@ pub fn main() -> Result<(), anyhow::Error> { } } TranspileFormat::SPIRV => { - let mut compilation = >::from_compilation(compilation)?; + let mut compilation = + >::from_compilation(compilation)?; compilation.validate()?; let output = compilation.compile(None)?; @@ -407,10 +408,7 @@ pub fn main() -> Result<(), anyhow::Error> { } }; - print!( - "{}", - ron::ser::to_string_pretty(&reflection, PrettyConfig::new())? - ); + print!("{}", serde_json::to_string_pretty(&reflection)?); } }