presets: initial preset contexts API

This commit is contained in:
chyyran 2024-02-08 21:33:17 -05:00
parent b2d8d084be
commit a14b36e05b
8 changed files with 464 additions and 55 deletions

57
Cargo.lock generated
View file

@ -531,16 +531,16 @@ dependencies = [
"bitflags 1.3.2", "bitflags 1.3.2",
"clap_lex 0.2.4", "clap_lex 0.2.4",
"indexmap 1.9.3", "indexmap 1.9.3",
"strsim", "strsim 0.10.0",
"termcolor", "termcolor",
"textwrap", "textwrap",
] ]
[[package]] [[package]]
name = "clap" name = "clap"
version = "4.4.18" version = "4.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e578d6ec4194633722ccf9544794b71b1385c3c027efe0c55db226fc880865c" checksum = "80c21025abd42669a92efc996ef13cfb2c5c627858421ea58d5c3b331a6c134f"
dependencies = [ dependencies = [
"clap_builder", "clap_builder",
"clap_derive", "clap_derive",
@ -548,21 +548,21 @@ dependencies = [
[[package]] [[package]]
name = "clap_builder" name = "clap_builder"
version = "4.4.18" version = "4.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4df4df40ec50c46000231c914968278b1eb05098cf8f1b3a518a95030e71d1c7" checksum = "458bf1f341769dfcf849846f65dffdf9146daa56bcd2a47cb4e1de9915567c99"
dependencies = [ dependencies = [
"anstream", "anstream",
"anstyle", "anstyle",
"clap_lex 0.6.0", "clap_lex 0.7.0",
"strsim", "strsim 0.11.0",
] ]
[[package]] [[package]]
name = "clap_derive" name = "clap_derive"
version = "4.4.7" version = "4.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf9804afaaf59a91e75b022a30fb7229a7901f60c755489cc61c9b423b836442" checksum = "307bc0538d5f0f83b8248db3087aa92fe504e4691294d0c96c0eabc33f47ba47"
dependencies = [ dependencies = [
"heck", "heck",
"proc-macro2", "proc-macro2",
@ -581,9 +581,9 @@ dependencies = [
[[package]] [[package]]
name = "clap_lex" name = "clap_lex"
version = "0.6.0" version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1" checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce"
[[package]] [[package]]
name = "cmake" name = "cmake"
@ -927,7 +927,7 @@ dependencies = [
"ident_case", "ident_case",
"proc-macro2", "proc-macro2",
"quote", "quote",
"strsim", "strsim 0.10.0",
"syn 1.0.109", "syn 1.0.109",
] ]
@ -1355,9 +1355,9 @@ dependencies = [
[[package]] [[package]]
name = "glslang-sys" name = "glslang-sys"
version = "0.3.1" version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d76f2d75ad6e8a12c26e77ed6443a9369ef7957daf361e751c3489a97f8b816" checksum = "6a47e052f086ec9b43df0bca02c1675c2a89bceb5386dd64382dc36143930985"
dependencies = [ dependencies = [
"cc", "cc",
"glob", "glob",
@ -1591,12 +1591,12 @@ dependencies = [
[[package]] [[package]]
name = "is-terminal" name = "is-terminal"
version = "0.4.10" version = "0.4.11"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0bad00257d07be169d870ab665980b06cdb366d792ad690bf2e76876dc503455" checksum = "fe8f25ce1159c7740ff0b9b2f5cdf4a8428742ba7c112b9f20f22cd5219c7dab"
dependencies = [ dependencies = [
"hermit-abi 0.3.5", "hermit-abi 0.3.5",
"rustix", "libc",
"windows-sys 0.52.0", "windows-sys 0.52.0",
] ]
@ -1630,9 +1630,9 @@ checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130"
[[package]] [[package]]
name = "jobserver" name = "jobserver"
version = "0.1.27" version = "0.1.28"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8c37f63953c4c63420ed5fd3d6d398c719489b9f872b9fa683262f8edd363c7d" checksum = "ab46a6e9526ddef3ae7f787c06f0f2600639ba80ea3eade3d8e670a2230f51d6"
dependencies = [ dependencies = [
"libc", "libc",
] ]
@ -1747,7 +1747,7 @@ name = "librashader-build-script"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"cbindgen", "cbindgen",
"clap 4.4.18", "clap 4.5.0",
] ]
[[package]] [[package]]
@ -1836,6 +1836,9 @@ dependencies = [
"nom", "nom",
"nom_locate", "nom_locate",
"num-traits", "num-traits",
"once_cell",
"regex",
"rustc-hash",
"thiserror", "thiserror",
] ]
@ -2980,7 +2983,7 @@ dependencies = [
"ab_glyph", "ab_glyph",
"log", "log",
"memmap2 0.9.4", "memmap2 0.9.4",
"smithay-client-toolkit 0.18.0", "smithay-client-toolkit 0.18.1",
"tiny-skia 0.11.4", "tiny-skia 0.11.4",
] ]
@ -3098,9 +3101,9 @@ dependencies = [
[[package]] [[package]]
name = "smithay-client-toolkit" name = "smithay-client-toolkit"
version = "0.18.0" version = "0.18.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60e3d9941fa3bacf7c2bf4b065304faa14164151254cd16ce1b1bc8fc381600f" checksum = "922fd3eeab3bd820d76537ce8f582b1cf951eceb5475c28500c7457d9d17f53a"
dependencies = [ dependencies = [
"bitflags 2.4.2", "bitflags 2.4.2",
"calloop 0.12.4", "calloop 0.12.4",
@ -3194,6 +3197,12 @@ version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
[[package]]
name = "strsim"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ee073c9e4cd00e28217186dbe12796d692868f432bf2e97ee73bed0c56dfa01"
[[package]] [[package]]
name = "syn" name = "syn"
version = "1.0.109" version = "1.0.109"
@ -4221,7 +4230,7 @@ dependencies = [
"redox_syscall 0.3.5", "redox_syscall 0.3.5",
"rustix", "rustix",
"sctk-adwaita 0.8.1", "sctk-adwaita 0.8.1",
"smithay-client-toolkit 0.18.0", "smithay-client-toolkit 0.18.1",
"smol_str", "smol_str",
"unicode-segmentation", "unicode-segmentation",
"wasm-bindgen", "wasm-bindgen",

View file

@ -17,7 +17,10 @@ nom = "7.1.1"
nom_locate = "4.0.0" nom_locate = "4.0.0"
librashader-common = { path = "../librashader-common", version = "0.2.0-beta.7" } librashader-common = { path = "../librashader-common", version = "0.2.0-beta.7" }
num-traits = "0.2" num-traits = "0.2"
once_cell = "1"
# we don't need unicode
regex = { version = "1", default-features = false, features = ["perf"] }
rustc-hash = "1.1.0"
[features] [features]
parse_legacy_glsl = [] parse_legacy_glsl = []

View file

@ -8,6 +8,8 @@
//! //!
//! Re-exported as [`librashader::presets`](https://docs.rs/librashader/latest/librashader/presets/index.html). //! Re-exported as [`librashader::presets`](https://docs.rs/librashader/latest/librashader/presets/index.html).
#![allow(stable_features)]
#![feature(os_str_bytes)]
#![allow(unstable_name_collisions)] #![allow(unstable_name_collisions)]
mod error; mod error;
@ -16,4 +18,5 @@ mod parse;
mod preset; mod preset;
pub use error::*; pub use error::*;
pub use parse::context;
pub use preset::*; pub use preset::*;

View file

@ -0,0 +1,358 @@
use nom::AsBytes;
use once_cell::sync::Lazy;
use regex::bytes::Regex;
use rustc_hash::FxHashMap;
use std::collections::VecDeque;
use std::ffi::{OsStr, OsString};
use std::fmt::{Debug, Display, Formatter, Write};
use std::hash::Hash;
use std::ops::Add;
use std::path::{Component, Path, PathBuf};
#[repr(u32)]
#[derive(Debug, Copy, Clone)]
pub enum VideoDriver {
None = 0,
GlCore,
Gl,
Vulkan,
Direct3D11,
Direct3D9Hlsl,
Direct3D12,
Metal,
}
impl Display for VideoDriver {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
VideoDriver::None => f.write_str("null"),
VideoDriver::GlCore => f.write_str("glcore"),
VideoDriver::Gl => f.write_str("gl"),
VideoDriver::Vulkan => f.write_str("vulkan"),
VideoDriver::Direct3D11 => f.write_str("d3d11"),
VideoDriver::Direct3D9Hlsl => f.write_str("d3d9_hlsl"),
VideoDriver::Direct3D12 => f.write_str("d3d12"),
VideoDriver::Metal => f.write_str("metal"),
}
}
}
#[repr(u32)]
#[derive(Debug, Copy, Clone)]
pub enum ShaderExtension {
Slang = 0,
Glsl,
Cg,
}
impl Display for ShaderExtension {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
ShaderExtension::Slang => f.write_str("slang"),
ShaderExtension::Glsl => f.write_str("glsl"),
ShaderExtension::Cg => f.write_str("cg"),
}
}
}
#[repr(u32)]
#[derive(Debug, Copy, Clone)]
pub enum PresetExtension {
Slangp = 0,
Glslp,
Cgp,
}
impl Display for PresetExtension {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
PresetExtension::Slangp => f.write_str("slangp"),
PresetExtension::Glslp => f.write_str("glslp"),
PresetExtension::Cgp => f.write_str("cgp"),
}
}
}
#[repr(u32)]
#[derive(Debug, Copy, Clone)]
pub enum Rotation {
/// Zero
Zero = 0,
/// 90 degrees
Right = 1,
/// 180 degrees
Straight = 2,
/// 270 degrees
Reflex = 3,
}
impl Add for Rotation {
type Output = Rotation;
fn add(self, rhs: Self) -> Self::Output {
let lhs = self as u32;
let out = lhs + rhs as u32;
let out = out % 4;
match out {
0 => Rotation::Zero,
1 => Rotation::Right,
2 => Rotation::Straight,
3 => Rotation::Reflex,
_ => unreachable!(),
}
}
}
impl Display for Rotation {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
Rotation::Zero => f.write_str("0"),
Rotation::Right => f.write_str("90"),
Rotation::Straight => f.write_str("180"),
Rotation::Reflex => f.write_str("270"),
}
}
}
#[repr(u32)]
#[derive(Debug, Copy, Clone)]
pub enum Orientation {
Vertical = 0,
Horizontal,
}
impl Display for Orientation {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
Orientation::Vertical => f.write_str("VERT"),
Orientation::Horizontal => f.write_str("HORZ"),
}
}
}
#[derive(Debug, Clone)]
pub enum ContextItem {
ContentDirectory(String),
CoreName(String),
GameName(String),
Preset(String),
PresetDirectory(String),
VideoDriver(VideoDriver),
VideoDriverShaderExtension(ShaderExtension),
VideoDriverPresetExtension(PresetExtension),
CoreRequestedRotation(Rotation),
AllowCoreRotation(bool),
UserRotation(Rotation),
FinalRotation(Rotation),
ScreenOrientation(Rotation),
ViewAspectOrientation(Orientation),
CoreAspectOrientation(Orientation),
ExternContext(String, String),
}
impl ContextItem {
fn toggle_str(v: bool) -> &'static str {
if v {
"ON"
} else {
"OFF"
}
}
pub fn key(&self) -> &str {
match self {
ContextItem::ContentDirectory(_) => "CONTENT-DIR",
ContextItem::CoreName(_) => "CORE",
ContextItem::GameName(_) => "GAME",
ContextItem::Preset(_) => "PRESET",
ContextItem::PresetDirectory(_) => "PRESET_DIR",
ContextItem::VideoDriver(_) => "VID-DRV",
ContextItem::CoreRequestedRotation(_) => "CORE-REQ-ROT",
ContextItem::AllowCoreRotation(_) => "VID-ALLOW-CORE-ROT",
ContextItem::UserRotation(_) => "VID-USER-ROT",
ContextItem::FinalRotation(_) => "VID-FINAL-ROT",
ContextItem::ScreenOrientation(_) => "SCREEN-ORIENT",
ContextItem::ViewAspectOrientation(_) => "VIEW-ASPECT-ORIENT",
ContextItem::CoreAspectOrientation(_) => "CORE-ASPECT-ORIENT",
ContextItem::VideoDriverShaderExtension(_) => "VID-DRV-SHADER-EXT",
ContextItem::VideoDriverPresetExtension(_) => "VID-DRV-PRESET-EXT",
ContextItem::ExternContext(key, _) => key,
}
}
}
impl Display for ContextItem {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
ContextItem::ContentDirectory(v) => f.write_str(v),
ContextItem::CoreName(v) => f.write_str(v),
ContextItem::GameName(v) => f.write_str(v),
ContextItem::Preset(v) => f.write_str(v),
ContextItem::PresetDirectory(v) => f.write_str(v),
ContextItem::VideoDriver(v) => f.write_fmt(format_args!("{}", v)),
ContextItem::CoreRequestedRotation(v) => {
f.write_fmt(format_args!("{}-{}", self.key(), v))
}
ContextItem::AllowCoreRotation(v) => f.write_fmt(format_args!(
"{}-{}",
self.key(),
ContextItem::toggle_str(*v)
)),
ContextItem::UserRotation(v) => f.write_fmt(format_args!("{}-{}", self.key(), v)),
ContextItem::FinalRotation(v) => f.write_fmt(format_args!("{}-{}", self.key(), v)),
ContextItem::ScreenOrientation(v) => f.write_fmt(format_args!("{}-{}", self.key(), v)),
ContextItem::ViewAspectOrientation(v) => {
f.write_fmt(format_args!("{}-{}", self.key(), v))
}
ContextItem::CoreAspectOrientation(v) => {
f.write_fmt(format_args!("{}-{}", self.key(), v))
}
ContextItem::VideoDriverShaderExtension(v) => f.write_fmt(format_args!("{}", v)),
ContextItem::VideoDriverPresetExtension(v) => f.write_fmt(format_args!("{}", v)),
ContextItem::ExternContext(_, v) => f.write_fmt(format_args!("{}", v)),
}
}
}
/// A builder for preset wildcard context.
///
/// Any items added after will have higher priority
/// when passed to the shader preset parser.
///
/// When passed to the preset parser, the preset parser
/// will automatically add inferred items at lowest priority.
///
/// Any items added by the user will override the automatically
/// inferred items.
#[derive(Debug, Clone)]
pub struct WildcardContext(VecDeque<ContextItem>);
impl WildcardContext {
/// Create a new wildcard context.
pub fn new() -> Self {
Self(VecDeque::new())
}
/// Prepend an item to the context builder.
pub fn prepend_item(&mut self, item: ContextItem) {
self.0.push_front(item);
}
/// Append an item to the context builder.
/// The new item will take precedence over all items added before it.
pub fn append_item(&mut self, item: ContextItem) {
self.0.push_back(item);
}
/// Prepend sensible defaults for the given video driver.
///
/// Any values added, either previously or afterwards will not be overridden.
pub fn add_video_driver_defaults(&mut self, video_driver: VideoDriver) {
self.0.push_front(ContextItem::VideoDriverPresetExtension(
PresetExtension::Slangp,
));
self.0.push_front(ContextItem::VideoDriverShaderExtension(
ShaderExtension::Slang,
));
self.0.push_front(ContextItem::VideoDriver(video_driver));
}
/// Prepend default entries from the path of the preset.
///
/// Any values added, either previously or afterwards will not be overridden.
pub fn add_path_defaults(&mut self, path: impl AsRef<Path>) {
let path = path.as_ref();
if let Some(preset_name) = path.file_stem() {
let preset_name = preset_name.to_string_lossy();
self.0.push_front(ContextItem::Preset(preset_name.into()))
}
if let Some(preset_dir_name) = path.parent().and_then(|p| {
if !p.is_dir() {
return None;
};
p.file_name()
}) {
let preset_dir_name = preset_dir_name.to_string_lossy();
self.0
.push_front(ContextItem::PresetDirectory(preset_dir_name.into()))
}
}
pub(crate) fn to_hashmap(mut self) -> FxHashMap<String, String> {
let mut map = FxHashMap::default();
let last_user_rot = self
.0
.iter()
.rfind(|i| matches!(i, ContextItem::UserRotation(_)));
let last_core_rot = self
.0
.iter()
.rfind(|i| matches!(i, ContextItem::CoreRequestedRotation(_)));
let final_rot = match (last_core_rot, last_user_rot) {
(Some(ContextItem::UserRotation(u)), None) => Some(ContextItem::FinalRotation(*u)),
(None, Some(ContextItem::CoreRequestedRotation(c))) => {
Some(ContextItem::FinalRotation(*c))
}
(Some(ContextItem::UserRotation(u)), Some(ContextItem::CoreRequestedRotation(c))) => {
Some(ContextItem::FinalRotation(*u + *c))
}
_ => None,
};
if let Some(final_rot) = final_rot {
self.prepend_item(final_rot);
}
for item in self.0 {
map.insert(String::from(item.key()), item.to_string());
}
map
}
}
pub fn apply_context(path: &mut PathBuf, context: &FxHashMap<String, String>) {
static WILDCARD_REGEX: Lazy<Regex> = Lazy::new(|| Regex::new("\\$([A-Z-_]+)\\$").unwrap());
if context.is_empty() {
return;
}
// Don't want to do any extra work if there's no match.
if !WILDCARD_REGEX.is_match(path.as_os_str().as_encoded_bytes()) {
return;
}
let mut new_path = PathBuf::with_capacity(path.capacity());
for component in path.components() {
match component {
Component::Normal(path) => {
let haystack = path.as_encoded_bytes();
let replaced =
WILDCARD_REGEX.replace_all(haystack, |caps: &regex::bytes::Captures| {
let Some(name) = caps.get(1) else {
return caps[0].to_vec();
};
let Ok(key) = std::str::from_utf8(name.as_bytes()) else {
return caps[0].to_vec();
};
if let Some(replacement) = context.get(key) {
return OsString::from(replacement.to_string()).into_encoded_bytes();
}
return caps[0].to_vec();
});
// SAFETY: The original source is valid encoded bytes, and our replacement is
// valid encoded bytes. This upholds the safety requirements of `from_encoded_bytes_unchecked`.
new_path.push(unsafe { OsStr::from_encoded_bytes_unchecked(&replaced.as_ref()) })
}
_ => new_path.push(component),
}
}
// If no wildcards are found within the path, or the path after replacing the wildcards does not exist on disk, the path returned will be unaffected.
if let Ok(true) = new_path.try_exists() {
*path = new_path;
}
}

View file

@ -4,6 +4,7 @@ use std::path::Path;
use nom_locate::LocatedSpan; use nom_locate::LocatedSpan;
use std::str; use std::str;
pub mod context;
mod preset; mod preset;
mod token; mod token;
mod value; mod value;
@ -12,6 +13,7 @@ pub(crate) type Span<'a> = LocatedSpan<&'a str>;
pub(crate) use token::Token; pub(crate) use token::Token;
use crate::error::ParsePresetError; use crate::error::ParsePresetError;
use crate::parse::context::{VideoDriver, WildcardContext};
use crate::parse::preset::resolve_values; use crate::parse::preset::resolve_values;
use crate::parse::value::parse_preset; use crate::parse::value::parse_preset;
use crate::ShaderPreset; use crate::ShaderPreset;
@ -22,12 +24,37 @@ pub(crate) fn remove_if<T>(values: &mut Vec<T>, f: impl FnMut(&T) -> bool) -> Op
impl ShaderPreset { impl ShaderPreset {
/// Try to parse the shader preset at the given path. /// Try to parse the shader preset at the given path.
///
/// This will add path defaults to the wildcard resolution context.
pub fn try_parse(path: impl AsRef<Path>) -> Result<ShaderPreset, ParsePresetError> { pub fn try_parse(path: impl AsRef<Path>) -> Result<ShaderPreset, ParsePresetError> {
ShaderPreset::try_parse_with_context(path, HashMap::new()) let mut context = WildcardContext::new();
context.add_path_defaults(path.as_ref());
let values = parse_preset(path, WildcardContext::new())?;
Ok(resolve_values(values))
} }
/// Try to parse the shader preset at the given path. /// Try to parse the shader preset at the given path.
pub fn try_parse_with_context(path: impl AsRef<Path>, context: HashMap<String, String>) -> Result<ShaderPreset, ParsePresetError> { ///
/// This will add path and driver defaults to the wildcard resolution context.
pub fn try_parse_with_driver_context(
path: impl AsRef<Path>,
driver: VideoDriver,
) -> Result<ShaderPreset, ParsePresetError> {
let mut context = WildcardContext::new();
context.add_path_defaults(path.as_ref());
context.add_video_driver_defaults(driver);
let values = parse_preset(path, context)?;
Ok(resolve_values(values))
}
/// Try to parse the shader preset at the given path, with the exact provided context.
///
/// This function does not change any of the values in the provided context, except calculating `VID-FINAL-ROT`
/// if `CORE-REQ-ROT` and `VID-USER-ROT` is present.
pub fn try_parse_with_context(
path: impl AsRef<Path>,
context: WildcardContext,
) -> Result<ShaderPreset, ParsePresetError> {
let values = parse_preset(path, context)?; let values = parse_preset(path, context)?;
Ok(resolve_values(values)) Ok(resolve_values(values))
} }

View file

@ -1,5 +1,5 @@
use crate::error::{ParseErrorKind, ParsePresetError}; use crate::error::{ParseErrorKind, ParsePresetError};
use crate::parse::{remove_if, Span, Token}; use crate::parse::{context, remove_if, Span, Token};
use crate::{ScaleFactor, ScaleType}; use crate::{ScaleFactor, ScaleType};
use nom::bytes::complete::tag; use nom::bytes::complete::tag;
use nom::character::complete::digit1; use nom::character::complete::digit1;
@ -11,12 +11,14 @@ use num_traits::cast::ToPrimitive;
use crate::parse::token::do_lex; use crate::parse::token::do_lex;
use librashader_common::{FilterMode, WrapMode}; use librashader_common::{FilterMode, WrapMode};
use rustc_hash::FxHashMap;
use std::fs::File; use std::fs::File;
use std::io::Read; use std::io::Read;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::str::FromStr; use std::str::FromStr;
use crate::extract_if::MakeExtractIf; use crate::extract_if::MakeExtractIf;
use crate::parse::context::WildcardContext;
#[derive(Debug)] #[derive(Debug)]
pub enum Value { pub enum Value {
@ -154,7 +156,7 @@ pub const SHADER_MAX_REFERENCE_DEPTH: usize = 16;
fn load_child_reference_strings( fn load_child_reference_strings(
root_references: Vec<PathBuf>, root_references: Vec<PathBuf>,
root_path: impl AsRef<Path>, root_path: impl AsRef<Path>,
context: &HashMap<String, String> context: &FxHashMap<String, String>,
) -> Result<Vec<(PathBuf, String)>, ParsePresetError> { ) -> Result<Vec<(PathBuf, String)>, ParsePresetError> {
let root_path = root_path.as_ref(); let root_path = root_path.as_ref();
@ -170,7 +172,7 @@ fn load_child_reference_strings(
// enter the current root // enter the current root
reference_depth += 1; reference_depth += 1;
// canonicalize current root // canonicalize current root
apply_context(&mut reference_root, context); context::apply_context(&mut reference_root, context);
let reference_root = reference_root let reference_root = reference_root
.canonicalize() .canonicalize()
.map_err(|e| ParsePresetError::IOError(reference_root.to_path_buf(), e))?; .map_err(|e| ParsePresetError::IOError(reference_root.to_path_buf(), e))?;
@ -179,11 +181,11 @@ fn load_child_reference_strings(
// println!("Resolving {referenced_paths:?} against {reference_root:?}."); // println!("Resolving {referenced_paths:?} against {reference_root:?}.");
for path in referenced_paths { for path in referenced_paths {
let mut path = reference_root let mut path = reference_root.join(path.clone());
.join(path.clone()); context::apply_context(&mut path, context);
apply_context(&mut path, context);
let mut path = path.canonicalize() let mut path = path
.canonicalize()
.map_err(|e| ParsePresetError::IOError(path.clone(), e))?; .map_err(|e| ParsePresetError::IOError(path.clone(), e))?;
// println!("Opening {:?}", path); // println!("Opening {:?}", path);
let mut reference_contents = String::new(); let mut reference_contents = String::new();
@ -209,14 +211,15 @@ fn load_child_reference_strings(
Ok(reference_strings.into()) Ok(reference_strings.into())
} }
fn apply_context(path: &mut PathBuf, context: &HashMap<String, String>) { pub(crate) fn parse_preset(
path: impl AsRef<Path>,
} context: WildcardContext,
) -> Result<Vec<Value>, ParsePresetError> {
pub fn parse_preset(path: impl AsRef<Path>, context: HashMap<String, String>) -> Result<Vec<Value>, ParsePresetError> {
let path = path.as_ref(); let path = path.as_ref();
let mut path = path.to_path_buf(); let mut path = path.to_path_buf();
apply_context(&mut path, &context); let context = context.to_hashmap();
context::apply_context(&mut path, &context);
let path = path let path = path
.canonicalize() .canonicalize()
@ -235,7 +238,7 @@ pub fn parse_preset(path: impl AsRef<Path>, context: HashMap<String, String>) ->
pub fn parse_values( pub fn parse_values(
mut tokens: Vec<Token>, mut tokens: Vec<Token>,
root_path: impl AsRef<Path>, root_path: impl AsRef<Path>,
context: HashMap<String, String> context: FxHashMap<String, String>,
) -> Result<Vec<Value>, ParsePresetError> { ) -> Result<Vec<Value>, ParsePresetError> {
let mut root_path = root_path.as_ref().to_path_buf(); let mut root_path = root_path.as_ref().to_path_buf();
if root_path.is_relative() { if root_path.is_relative() {

View file

@ -1,5 +1,7 @@
use glob::glob; use glob::glob;
use librashader_presets::context::{ContextItem, VideoDriver, WildcardContext};
use librashader_presets::ShaderPreset; use librashader_presets::ShaderPreset;
use std::collections::HashMap;
#[test] #[test]
fn parses_all_slang_presets() { fn parses_all_slang_presets() {
@ -17,3 +19,17 @@ fn parses_problematic() {
let path = "../test/Mega_Bezel_Packs/Duimon-Mega-Bezel/Presets/Advanced/Nintendo_NDS_DREZ/NDS-[DREZ]-[Native]-[ADV]-[Guest]-[Night].slangp"; let path = "../test/Mega_Bezel_Packs/Duimon-Mega-Bezel/Presets/Advanced/Nintendo_NDS_DREZ/NDS-[DREZ]-[Native]-[ADV]-[Guest]-[Night].slangp";
ShaderPreset::try_parse(path).expect(&format!("Failed to parse {}", path)); ShaderPreset::try_parse(path).expect(&format!("Failed to parse {}", path));
} }
#[test]
fn parses_wildcard() {
let path =
"../test/shaders_slang/bezel/Mega_Bezel/resource/wildcard-examples/Preset-01-Core.slangp";
let mut context = WildcardContext::new();
context.add_video_driver_defaults(VideoDriver::Vulkan);
context.append_item(ContextItem::CoreName(String::from("image display")));
ShaderPreset::try_parse_with_context(path, context)
.expect(&format!("Failed to parse {}", path));
}

View file

@ -1,5 +1,5 @@
use glslang::{CompilerOptions, ShaderInput};
use crate::error::ShaderCompileError; use crate::error::ShaderCompileError;
use glslang::{CompilerOptions, ShaderInput};
use librashader_preprocess::ShaderSource; use librashader_preprocess::ShaderSource;
#[cfg(feature = "serialize")] #[cfg(feature = "serialize")]
@ -37,27 +37,17 @@ pub(crate) fn compile_spirv(
source_language: glslang::SourceLanguage::GLSL, source_language: glslang::SourceLanguage::GLSL,
target: glslang::Target::Vulkan { target: glslang::Target::Vulkan {
version: glslang::VulkanVersion::Vulkan1_0, version: glslang::VulkanVersion::Vulkan1_0,
spirv_version: glslang::SpirvVersion::SPIRV1_0 spirv_version: glslang::SpirvVersion::SPIRV1_0,
}, },
version_profile: None, version_profile: None,
}; };
let vertex = glslang::ShaderSource::from(source.vertex.as_str()); let vertex = glslang::ShaderSource::from(source.vertex.as_str());
let vertex = ShaderInput::new( let vertex = ShaderInput::new(&vertex, glslang::ShaderStage::Vertex, &options, None)?;
&vertex,
glslang::ShaderStage::Vertex,
&options,
None,
)?;
let vertex = compiler.create_shader(vertex)?; let vertex = compiler.create_shader(vertex)?;
let fragment = glslang::ShaderSource::from(source.fragment.as_str()); let fragment = glslang::ShaderSource::from(source.fragment.as_str());
let fragment = ShaderInput::new( let fragment = ShaderInput::new(&fragment, glslang::ShaderStage::Fragment, &options, None)?;
&fragment,
glslang::ShaderStage::Fragment,
&options,
None,
)?;
let fragment = compiler.create_shader(fragment)?; let fragment = compiler.create_shader(fragment)?;
let vertex = Vec::from(vertex.compile()?); let vertex = Vec::from(vertex.compile()?);