presets: initial preset contexts API
This commit is contained in:
parent
b2d8d084be
commit
a14b36e05b
57
Cargo.lock
generated
57
Cargo.lock
generated
|
@ -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",
|
||||||
|
|
|
@ -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 = []
|
||||||
|
|
||||||
|
|
|
@ -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::*;
|
||||||
|
|
358
librashader-presets/src/parse/context.rs
Normal file
358
librashader-presets/src/parse/context.rs
Normal 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: ®ex::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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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))
|
||||||
}
|
}
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -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));
|
||||||
|
}
|
||||||
|
|
|
@ -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()?);
|
||||||
|
|
Loading…
Reference in a new issue