From 6b8449b4da3aa8cc5d64b95d78d53eb0d7397411 Mon Sep 17 00:00:00 2001 From: chyyran Date: Thu, 20 Oct 2022 22:52:34 -0400 Subject: [PATCH] preset: parse to config structs --- .idea/vcs.xml | 1 + librashader-presets/src/parse/mod.rs | 41 ++++++- librashader-presets/src/parse/preset.rs | 142 ++++++++++++++++++++++++ librashader-presets/src/parse/token.rs | 3 +- librashader-presets/src/parse/value.rs | 52 +++++---- librashader-presets/src/preset.rs | 25 +++-- target/.rustc_info.json | 2 +- 7 files changed, 229 insertions(+), 37 deletions(-) create mode 100644 librashader-presets/src/parse/preset.rs diff --git a/.idea/vcs.xml b/.idea/vcs.xml index 288b36b..df5842e 100644 --- a/.idea/vcs.xml +++ b/.idea/vcs.xml @@ -3,5 +3,6 @@ + \ No newline at end of file diff --git a/librashader-presets/src/parse/mod.rs b/librashader-presets/src/parse/mod.rs index 58b337a..365cde4 100644 --- a/librashader-presets/src/parse/mod.rs +++ b/librashader-presets/src/parse/mod.rs @@ -1,12 +1,45 @@ +use std::path::Path; use nom::{ExtendInto, Offset}; use nom_locate::LocatedSpan; use std::str; mod token; mod value; +mod preset; + +pub(crate) type Span<'a> = LocatedSpan<&'a str>; +pub(crate) use token::Token; +pub(crate) use value::Value; -pub type Span<'a> = LocatedSpan<&'a str>; use crate::error::ParsePresetError; -pub use token::do_lex; -pub use token::Token; -pub use value::parse_values; +use crate::parse::preset::resolve_values; +use crate::parse::value::parse_preset; +use crate::Preset; + +pub(crate) fn remove_if(values: &mut Vec, f: impl FnMut(&T) -> bool) -> Option { + values.iter() + .position(f) + .map(|idx| values.remove(idx)) +} + +impl Preset { + pub fn try_parse(path: impl AsRef) -> Result { + let values = parse_preset(path)?; + Ok(resolve_values(values)) + } +} + +#[cfg(test)] +mod test { + use std::path::PathBuf; + use crate::Preset; + + #[test] + pub fn parse_preset() { + let root = + PathBuf::from("test/slang-shaders/bezel/Mega_Bezel/Presets/Base_CRT_Presets/MBZ__3__STD__MEGATRON-NTSC.slangp"); + let basic = Preset::try_parse(root); + eprintln!("{:#?}", basic); + assert!(basic.is_ok()); + } +} \ No newline at end of file diff --git a/librashader-presets/src/parse/preset.rs b/librashader-presets/src/parse/preset.rs new file mode 100644 index 0000000..d9ccac1 --- /dev/null +++ b/librashader-presets/src/parse/preset.rs @@ -0,0 +1,142 @@ +use crate::parse::value::Value; +use crate::{WrapMode, FilterMode, Parameter, Preset, Scale2D, Scaling, ShaderConfig, TextureConfig}; +use crate::parse::remove_if; + +pub fn resolve_values(mut values: Vec) -> Preset { + let textures: Vec = values.drain_filter(|f| matches!(*f, Value::Texture { .. })) + .map(|value| { + if let Value::Texture { name, filter_mode, wrap_mode, mipmap, path } = value { + TextureConfig { + name, + path, + wrap_mode, + filter_mode, + mipmap + } + } else { + unreachable!("values should all be of type Texture") + } + }).collect(); + let parameters: Vec = values.drain_filter(|f| matches!(*f, Value::Parameter { .. })).map(|value| { + if let Value::Parameter(name, value) = value { + Parameter { + name, + value + } + } else { + unreachable!("values should be all of type parameters") + } + }).collect(); + + let mut shaders = Vec::new(); + let shader_count = remove_if(&mut values, |v| { + matches!(*v, Value::ShaderCount(_)) + }) + .map(|value| if let Value::ShaderCount(count) = value { count } else { unreachable!("value should be of type shader_count") }) + .unwrap_or(0); + + let feedback_pass = remove_if(&mut values, |v| { + matches!(*v, Value::FeedbackPass(_)) + }) + .map(|value| if let Value::FeedbackPass(pass) = value { pass } else { unreachable!("value should be of type feedback_pass") }) + .unwrap_or(0); + + for shader in 0..shader_count { + if let Some(Value::Shader(id, name)) = remove_if(&mut values, |v| matches!(*v, Value::Shader(shader_index, _) if shader_index == shader)) { + let shader_values: Vec = values.drain_filter(|v| v.shader_index() == Some(shader)).collect(); + let scale_type = shader_values.iter().find_map(|f| match f { + Value::ScaleType(_, value) => Some(*value), + _ => None + }); + + let mut scale_type_x = shader_values.iter().find_map(|f| match f { + Value::ScaleType(_, value) => Some(*value), + _ => None + }); + + let mut scale_type_y = shader_values.iter().find_map(|f| match f { + Value::ScaleType(_, value) => Some(*value), + _ => None + }); + + if scale_type.is_some() { + // scale takes priority + // https://github.com/libretro/RetroArch/blob/fcbd72dbf3579eb31721fbbf0d89a139834bcce9/gfx/video_shader_parse.c#L310 + scale_type_x = scale_type; + scale_type_y = scale_type; + } + + let scale_valid = scale_type_x.is_some() || scale_type_y.is_some(); + + let scale = shader_values.iter().find_map(|f| match f { + Value::Scale(_, value) => Some(*value), + _ => None + }); + + let mut scale_x = shader_values.iter().find_map(|f| match f { + Value::ScaleX(_, value) => Some(*value), + _ => None + }); + + let mut scale_y = shader_values.iter().find_map(|f| match f { + Value::ScaleY(_, value) => Some(*value), + _ => None + }); + + if scale.is_some() { + // scale takes priority + // https://github.com/libretro/RetroArch/blob/fcbd72dbf3579eb31721fbbf0d89a139834bcce9/gfx/video_shader_parse.c#L310 + scale_x = scale; + scale_y = scale; + } + + let mut shader = ShaderConfig { + id, + name, + alias: shader_values.iter().find_map(|f| match f { + Value::Alias(_, value) => Some(value.to_string()), + _ => None + }), + filter: shader_values.iter().find_map(|f| match f { + Value::FilterMode(_, value) => Some(*value), + _ => None + }).unwrap_or(FilterMode::default()), + wrap_mode: shader_values.iter().find_map(|f| match f { + Value::WrapMode(_, value) => Some(*value), + _ => None + }).unwrap_or(WrapMode::default()), + frame_count_mod: shader_values.iter().find_map(|f| match f { + Value::FrameCountMod(_, value) => Some(*value), + _ => None + }).unwrap_or(0), + srgb_framebuffer: shader_values.iter().find_map(|f| match f { + Value::SrgbFramebuffer(_, value) => Some(*value), + _ => None + }).unwrap_or(false), + float_framebuffer: shader_values.iter().find_map(|f| match f { + Value::FloatFramebuffer(_, value) => Some(*value), + _ => None + }).unwrap_or(false), + mipmap_input: shader_values.iter().find_map(|f| match f { + Value::MipmapInput(_, value) => Some(*value), + _ => None + }).unwrap_or(false), + scaling: Scale2D { + valid: scale_valid, + x: Scaling { scale_type: scale_type_x.unwrap_or_default(), factor: scale_x.unwrap_or_default() }, + y: Scaling { scale_type: scale_type_y.unwrap_or_default(), factor: scale_y.unwrap_or_default() } + } + }; + + shaders.push(shader) + } + } + + Preset { + shader_count, + feedback_pass, + shaders, + textures, + parameters + } +} \ No newline at end of file diff --git a/librashader-presets/src/parse/token.rs b/librashader-presets/src/parse/token.rs index 4714397..527ec61 100644 --- a/librashader-presets/src/parse/token.rs +++ b/librashader-presets/src/parse/token.rs @@ -155,8 +155,7 @@ pub fn do_lex(input: &str) -> Result, ParsePresetError> { #[cfg(test)] mod test { - use crate::parse::do_lex; - use crate::parse::token::{parse_key_value, parse_tokens, single_comment, Span}; + use crate::parse::token::{do_lex, parse_key_value, parse_tokens, single_comment, Span}; #[test] fn parses_single_line_comment() { diff --git a/librashader-presets/src/parse/value.rs b/librashader-presets/src/parse/value.rs index a08f95a..3c3ea91 100644 --- a/librashader-presets/src/parse/value.rs +++ b/librashader-presets/src/parse/value.rs @@ -1,5 +1,5 @@ use crate::error::{ParseErrorKind, ParsePresetError}; -use crate::parse::{Span, Token}; +use crate::parse::{remove_if, Span, Token}; use crate::{FilterMode, ScaleFactor, ScaleType, Scaling, WrapMode}; use nom::bytes::complete::tag; use nom::character::complete::digit1; @@ -11,6 +11,7 @@ use std::fs::File; use std::io::Read; use std::path::{Path, PathBuf}; use std::str::FromStr; +use crate::parse::token::do_lex; #[derive(Debug)] pub enum Value { @@ -38,6 +39,26 @@ pub enum Value { }, } +impl Value { + pub(crate) fn shader_index(&self) -> Option { + match self { + Value::Shader(i, _) => Some(*i), + Value::ScaleX(i, _) => Some(*i), + Value::ScaleY(i, _) => Some(*i), + Value::Scale(i, _) => Some(*i), + Value::ScaleType(i, _) => Some(*i), + Value::FilterMode(i, _) => Some(*i), + Value::WrapMode(i, _) => Some(*i), + Value::FrameCountMod(i, _) => Some(*i), + Value::FloatFramebuffer(i, _) => Some(*i), + Value::SrgbFramebuffer(i, _) => Some(*i), + Value::MipmapInput(i, _) => Some(*i), + Value::Alias(i, _) => Some(*i), + _ => None + } + } +} + fn from_int(input: Span) -> Result { i32::from_str(input.trim()).map_err(|_| { eprintln!("{input}"); @@ -135,7 +156,7 @@ fn load_child_reference_strings( .read_to_string(&mut reference_contents) .map_err(|e| ParsePresetError::IOError(reference_root.clone(), e))?; - let mut new_tokens = super::do_lex(&reference_contents)?; + let mut new_tokens = do_lex(&reference_contents)?; let mut new_references: Vec = new_tokens .drain_filter(|token| *token.key.fragment() == "#reference") .map(|value| PathBuf::from(*value.value.fragment())) @@ -195,7 +216,7 @@ pub fn parse_values( all_tokens.push((root_path.as_path(), tokens)); for (path, string) in child_strings.iter() { - let mut tokens = crate::parse::do_lex(string.as_ref())?; + let mut tokens = do_lex(string.as_ref())?; tokens.retain(|token| *token.key.fragment() != "#reference"); all_tokens.push((path.as_path(), tokens)) } @@ -272,34 +293,24 @@ pub fn parse_values( .collect(); for (texture, path) in textures { - let mipmap = tokens - .iter() - .position(|t| { - t.key.starts_with(*texture) - && t.key.ends_with("_mipmap") - && t.key.len() == texture.len() + "_mipmap".len() - }) - .map(|idx| tokens.remove(idx)) - .map_or_else(|| Ok(false), |v| from_bool(v.value))?; + let mipmap = remove_if(&mut tokens, |t| { + t.key.starts_with(*texture) + && t.key.ends_with("_mipmap") + && t.key.len() == texture.len() + "_mipmap".len() + }).map_or_else(|| Ok(false), |v| from_bool(v.value))?; - let linear = tokens - .iter() - .position(|t| { + let linear = remove_if(&mut tokens, |t| { t.key.starts_with(*texture) && t.key.ends_with("_linear") && t.key.len() == texture.len() + "_linear".len() }) - .map(|idx| tokens.remove(idx)) .map_or_else(|| Ok(false), |v| from_bool(v.value))?; - let wrap_mode = tokens - .iter() - .position(|t| { + let wrap_mode = remove_if(&mut tokens, |t| { t.key.starts_with(*texture) && t.key.ends_with("_wrap_mode") && t.key.len() == texture.len() + "_wrap_mode".len() }) - .map(|idx| tokens.remove(idx)) // NOPANIC: infallible .map_or_else( || WrapMode::default(), @@ -439,7 +450,6 @@ pub fn parse_values( continue; } - eprintln!("{}", token.key); // handle undeclared parameters after parsing everything else as a last resort. let param_val = from_float(token.value)?; values.push(Value::Parameter( diff --git a/librashader-presets/src/preset.rs b/librashader-presets/src/preset.rs index e592488..b878bcb 100644 --- a/librashader-presets/src/preset.rs +++ b/librashader-presets/src/preset.rs @@ -4,7 +4,7 @@ use std::path::PathBuf; use std::str::FromStr; #[repr(i32)] -#[derive(Default, Debug)] +#[derive(Copy, Clone, Default, Debug)] pub enum FilterMode { #[default] Linear = 0, @@ -13,7 +13,7 @@ pub enum FilterMode { } #[repr(i32)] -#[derive(Default, Debug)] +#[derive(Copy, Clone, Default, Debug)] pub enum WrapMode { #[default] ClampToBorder = 0, @@ -23,7 +23,7 @@ pub enum WrapMode { } #[repr(i32)] -#[derive(Default, Debug)] +#[derive(Default, Copy, Clone, Debug)] pub enum ScaleType { #[default] Input = 0, @@ -31,7 +31,7 @@ pub enum ScaleType { Viewport, } -#[derive(Debug)] +#[derive(Copy, Clone, Debug)] pub enum ScaleFactor { Float(f32), Absolute(i32), @@ -70,45 +70,52 @@ impl FromStr for ScaleType { } } +#[derive(Debug, Clone)] pub struct Scaling { pub scale_type: ScaleType, pub factor: ScaleFactor, } +#[derive(Debug, Clone)] pub struct Scale2D { pub valid: bool, pub x: Scaling, pub y: Scaling, } +#[derive(Debug, Clone)] pub struct ShaderConfig { - pub id: usize, - pub name: String, - pub alias: String, + pub id: i32, + pub name: PathBuf, + pub alias: Option, pub filter: FilterMode, pub wrap_mode: WrapMode, pub frame_count_mod: u32, pub srgb_framebuffer: bool, pub float_framebuffer: bool, - pub feedback_pass: i32, pub mipmap_input: bool, pub scaling: Scale2D, } +#[derive(Debug, Clone)] pub struct TextureConfig { pub name: String, pub path: PathBuf, pub wrap_mode: WrapMode, - pub filter: FilterMode, + pub filter_mode: FilterMode, pub mipmap: bool, } +#[derive(Debug, Clone)] pub struct Parameter { pub name: String, pub value: f32, } +#[derive(Debug, Clone)] pub struct Preset { + pub shader_count: i32, + pub feedback_pass: i32, // Everything is in Vecs because the expect number of values is well below 64. pub shaders: Vec, pub textures: Vec, diff --git a/target/.rustc_info.json b/target/.rustc_info.json index 5f43b7e..4f25988 100644 --- a/target/.rustc_info.json +++ b/target/.rustc_info.json @@ -1 +1 @@ -{"rustc_fingerprint":1842804115855352081,"outputs":{"10376369925670944939":{"success":true,"status":"","code":0,"stdout":"___.exe\nlib___.rlib\n___.dll\n___.dll\n___.lib\n___.dll\nC:\\Users\\ronny\\.rustup\\toolchains\\nightly-x86_64-pc-windows-msvc\ndebug_assertions\npanic=\"unwind\"\nproc_macro\ntarget_abi=\"\"\ntarget_arch=\"x86_64\"\ntarget_endian=\"little\"\ntarget_env=\"msvc\"\ntarget_family=\"windows\"\ntarget_feature=\"fxsr\"\ntarget_feature=\"llvm14-builtins-abi\"\ntarget_feature=\"sse\"\ntarget_feature=\"sse2\"\ntarget_has_atomic=\"16\"\ntarget_has_atomic=\"32\"\ntarget_has_atomic=\"64\"\ntarget_has_atomic=\"8\"\ntarget_has_atomic=\"ptr\"\ntarget_has_atomic_equal_alignment=\"16\"\ntarget_has_atomic_equal_alignment=\"32\"\ntarget_has_atomic_equal_alignment=\"64\"\ntarget_has_atomic_equal_alignment=\"8\"\ntarget_has_atomic_equal_alignment=\"ptr\"\ntarget_has_atomic_load_store=\"16\"\ntarget_has_atomic_load_store=\"32\"\ntarget_has_atomic_load_store=\"64\"\ntarget_has_atomic_load_store=\"8\"\ntarget_has_atomic_load_store=\"ptr\"\ntarget_os=\"windows\"\ntarget_pointer_width=\"64\"\ntarget_thread_local\ntarget_vendor=\"pc\"\nwindows\n","stderr":""},"4614504638168534921":{"success":true,"status":"","code":0,"stdout":"rustc 1.65.0-nightly (750bd1a7f 2022-09-14)\nbinary: rustc\ncommit-hash: 750bd1a7ff3e010611b97ee75d30b7cbf5f3a03c\ncommit-date: 2022-09-14\nhost: x86_64-pc-windows-msvc\nrelease: 1.65.0-nightly\nLLVM version: 15.0.0\n","stderr":""},"15697416045686424142":{"success":true,"status":"","code":0,"stdout":"___.exe\nlib___.rlib\n___.dll\n___.dll\n___.lib\n___.dll\n","stderr":""}},"successes":{}} \ No newline at end of file +{"rustc_fingerprint":1842804115855352081,"outputs":{"4614504638168534921":{"success":true,"status":"","code":0,"stdout":"rustc 1.65.0-nightly (750bd1a7f 2022-09-14)\nbinary: rustc\ncommit-hash: 750bd1a7ff3e010611b97ee75d30b7cbf5f3a03c\ncommit-date: 2022-09-14\nhost: x86_64-pc-windows-msvc\nrelease: 1.65.0-nightly\nLLVM version: 15.0.0\n","stderr":""},"15697416045686424142":{"success":true,"status":"","code":0,"stdout":"___.exe\nlib___.rlib\n___.dll\n___.dll\n___.lib\n___.dll\n","stderr":""},"10376369925670944939":{"success":true,"status":"","code":0,"stdout":"___.exe\nlib___.rlib\n___.dll\n___.dll\n___.lib\n___.dll\nC:\\Users\\ronny\\.rustup\\toolchains\\nightly-x86_64-pc-windows-msvc\ndebug_assertions\npanic=\"unwind\"\nproc_macro\ntarget_abi=\"\"\ntarget_arch=\"x86_64\"\ntarget_endian=\"little\"\ntarget_env=\"msvc\"\ntarget_family=\"windows\"\ntarget_feature=\"fxsr\"\ntarget_feature=\"llvm14-builtins-abi\"\ntarget_feature=\"sse\"\ntarget_feature=\"sse2\"\ntarget_has_atomic=\"16\"\ntarget_has_atomic=\"32\"\ntarget_has_atomic=\"64\"\ntarget_has_atomic=\"8\"\ntarget_has_atomic=\"ptr\"\ntarget_has_atomic_equal_alignment=\"16\"\ntarget_has_atomic_equal_alignment=\"32\"\ntarget_has_atomic_equal_alignment=\"64\"\ntarget_has_atomic_equal_alignment=\"8\"\ntarget_has_atomic_equal_alignment=\"ptr\"\ntarget_has_atomic_load_store=\"16\"\ntarget_has_atomic_load_store=\"32\"\ntarget_has_atomic_load_store=\"64\"\ntarget_has_atomic_load_store=\"8\"\ntarget_has_atomic_load_store=\"ptr\"\ntarget_os=\"windows\"\ntarget_pointer_width=\"64\"\ntarget_thread_local\ntarget_vendor=\"pc\"\nwindows\n","stderr":""}},"successes":{}} \ No newline at end of file