reflect: allow indexed and non-indexed semantics to be serialized and deserialized as strings

This commit is contained in:
chyyran 2024-09-26 17:37:45 -04:00 committed by Ronny Chan
parent 1537c1bcd7
commit a72a593029
4 changed files with 182 additions and 36 deletions

23
Cargo.lock generated
View file

@ -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"

View file

@ -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<T> {
/// 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<T, I = usize> {
/// The semantics of this unit.
pub semantics: T,
@ -498,12 +519,159 @@ impl From<Semantic<TextureSemantics>> 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<ShortString, VariableMeta>,
#[cfg_attr(feature = "serde", serde(rename = "unique"))]
/// A map of unique semantics to uniform binding metadata.
pub unique_meta: FastHashMap<UniqueSemantics, VariableMeta>,
#[cfg_attr(feature = "serde", serde(rename = "texture"))]
/// A map of texture semantics to texture binding points.
pub texture_meta: FastHashMap<Semantic<TextureSemantics>, 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<Semantic<TextureSemantics>, 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<TextureSemantics>;
fn expecting(&self, formatter: &mut Formatter) -> std::fmt::Result {
formatter.write_str("a string of the form (Semantic)N?")
}
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
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::<usize>() 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<TextureSemantics> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
deserializer.deserialize_str(TextureSemanticVisitor)
}
}
impl Serialize for Semantic<TextureSemantics> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
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<UniqueSemantics, ()>;
fn expecting(&self, formatter: &mut Formatter) -> std::fmt::Result {
formatter.write_str("a valid uniform semantic name")
}
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
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<UniqueSemantics, ()> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_str(self.semantics.as_str())
}
}
impl<'de> Deserialize<'de> for Semantic<UniqueSemantics, ()> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
deserializer.deserialize_str(UniqueSemanticsVisitor)
}
}
}

View file

@ -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"]

View file

@ -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 = <librashader::reflect::targets::MSL as FromCompilation<
SpirvCompilation,
SpirvCross,
>>::from_compilation(compilation)?;
let mut compilation =
<librashader::reflect::targets::MSL as FromCompilation<
SpirvCompilation,
SpirvCross,
>>::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 = <librashader::reflect::targets::SPIRV as FromCompilation<
SpirvCompilation,
SpirvCross,
>>::from_compilation(compilation)?;
let mut compilation =
<librashader::reflect::targets::SPIRV as FromCompilation<
SpirvCompilation,
SpirvCross,
>>::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)?);
}
}