presets: allow quark source paths

This commit is contained in:
chyyran 2023-02-23 22:55:39 -05:00
parent b00f1f92f4
commit 34b54b18e1
14 changed files with 122 additions and 69 deletions

8
Cargo.lock generated
View file

@ -1277,6 +1277,7 @@ dependencies = [
name = "librashader-presets"
version = "0.1.3"
dependencies = [
"bml",
"glob",
"librashader-common 0.1.3",
"nom",
@ -1285,13 +1286,6 @@ dependencies = [
"thiserror",
]
[[package]]
name = "librashader-quark"
version = "0.1.0"
dependencies = [
"bml",
]
[[package]]
name = "librashader-reflect"
version = "0.1.3"

View file

@ -12,7 +12,6 @@ members = [
"librashader-runtime-vk",
"librashader-cache",
"librashader-capi",
"librashader-quark",
"librashader-build-script",
]

View file

@ -18,6 +18,8 @@ nom_locate = "4.0.0"
librashader-common = { path = "../librashader-common", version = "0.1.3" }
num-traits = "0.2"
bml = "0.3.1"
[features]
parse_legacy_glsl = []

View file

@ -30,6 +30,9 @@ pub enum ParsePresetError {
/// The shader preset did not contain valid UTF-8 bytes.
#[error("expected utf8 bytes but got invalid utf8")]
Utf8Error(Vec<u8>),
/// Error parsing BML file.
#[error("error parsing quark bml")]
BmlError(#[from] bml::BmlError)
}
/// The kind of error that may occur in parsing.

View file

@ -12,5 +12,7 @@
mod error;
mod parse;
mod preset;
mod quark;
pub use error::*;
pub use preset::*;

View file

@ -9,6 +9,9 @@ mod value;
pub(crate) type Span<'a> = LocatedSpan<&'a str>;
pub(crate) use token::Token;
pub(crate) use value::Value;
pub(crate) use value::ShaderType;
pub(crate) use value::ShaderStage;
use crate::error::ParsePresetError;
use crate::parse::preset::resolve_values;

View file

@ -1,7 +1,7 @@
use librashader_common::ImageFormat;
use crate::parse::remove_if;
use crate::parse::{remove_if, ShaderType};
use crate::parse::value::Value;
use crate::{ParameterConfig, Scale2D, Scaling, ShaderPassConfig, ShaderPreset, TextureConfig};
use crate::{ParameterConfig, Scale2D, Scaling, ShaderPassConfig, ShaderPath, ShaderPreset, TextureConfig};
pub fn resolve_values(mut values: Vec<Value>) -> ShaderPreset {
let textures: Vec<TextureConfig> = values
@ -60,9 +60,9 @@ pub fn resolve_values(mut values: Vec<Value>) -> ShaderPreset {
.unwrap_or(0);
for shader in 0..shader_count {
if let Some(Value::Shader(id, name)) = remove_if(
if let Some(Value::Shader(id, ShaderType::Slang, name)) = remove_if(
&mut values,
|v| matches!(*v, Value::Shader(shader_index, _) if shader_index == shader),
|v| matches!(*v, Value::Shader(shader_index, ShaderType::Slang, _) if shader_index == shader),
) {
let shader_values: Vec<Value> = values
.drain_filter(|v| v.shader_index() == Some(shader))
@ -139,7 +139,7 @@ pub fn resolve_values(mut values: Vec<Value>) -> ShaderPreset {
let shader = ShaderPassConfig {
id,
name,
source_path: ShaderPath::Slang(name),
alias: shader_values.iter().find_map(|f| match f {
Value::Alias(_, value) => Some(value.to_string()),
_ => None,

View file

@ -16,11 +16,25 @@ use std::io::Read;
use std::path::{Path, PathBuf};
use std::str::FromStr;
#[derive(Debug)]
pub enum ShaderStage {
Fragment,
Vertex,
Geometry
}
#[derive(Debug)]
pub enum ShaderType {
Slang,
Quark(ShaderStage)
}
#[derive(Debug)]
pub enum Value {
ShaderCount(i32),
FeedbackPass(i32),
Shader(i32, PathBuf),
Shader(i32, ShaderType, PathBuf),
ScaleX(i32, ScaleFactor),
ScaleY(i32, ScaleFactor),
Scale(i32, ScaleFactor),
@ -47,7 +61,7 @@ pub enum Value {
impl Value {
pub(crate) fn shader_index(&self) -> Option<i32> {
match self {
Value::Shader(i, _) => Some(*i),
Value::Shader(i, _, _) => Some(*i),
Value::ScaleX(i, _) => Some(*i),
Value::ScaleY(i, _) => Some(*i),
Value::Scale(i, _) => Some(*i),
@ -202,6 +216,7 @@ fn load_child_reference_strings(
Ok(reference_strings.into())
}
// todo: move this to slang
pub fn parse_preset(path: impl AsRef<Path>) -> Result<Vec<Value>, ParsePresetError> {
let path = path.as_ref();
let path = path
@ -217,6 +232,7 @@ pub fn parse_preset(path: impl AsRef<Path>) -> Result<Vec<Value>, ParsePresetErr
parse_values(tokens, path)
}
// todo: move this to slang
pub fn parse_values(
mut tokens: Vec<Token>,
root_path: impl AsRef<Path>,
@ -299,7 +315,7 @@ pub fn parse_values(
relative_path
.canonicalize()
.map_err(|e| ParsePresetError::IOError(relative_path.clone(), e))?;
values.push(Value::Shader(index, relative_path))
values.push(Value::Shader(index, ShaderType::Slang, relative_path))
}
}

View file

@ -10,7 +10,7 @@ pub struct ShaderPassConfig {
/// The index of the shader pass relative to its parent preset.
pub id: i32,
/// The fully qualified path to the shader pass source file.
pub name: PathBuf,
pub source_path: ShaderPath,
/// The alias of the shader pass if available.
pub alias: Option<String>,
/// The filtering mode that this shader pass should expect.
@ -41,6 +41,15 @@ impl ShaderPassConfig {
}
}
#[derive(Clone, Debug)]
/// The path to a shader.
pub enum ShaderPath {
/// Slang combined shader
Slang(PathBuf),
/// Quark split vertex/fragment shaders.
Quark { vertex: Option<PathBuf>, fragment: Option<PathBuf> }
}
#[repr(i32)]
#[derive(Default, Copy, Clone, Debug)]
/// The scaling type for the shader pass.

View file

@ -0,0 +1,68 @@
use std::error::Error;
use std::fs::File;
use std::io::Read;
use std::path::{Path, PathBuf};
use std::str::FromStr;
use bml::BmlNode;
use librashader_common::FilterMode;
use crate::parse::{ShaderStage, ShaderType, Value};
use crate::ParsePresetError;
fn parse_bml_node(path: impl AsRef<Path>) -> Result<BmlNode, ParsePresetError> {
let path = path.as_ref();
let path = path
.canonicalize()
.map_err(|e| ParsePresetError::IOError(path.to_path_buf(), e))?;
let mut manifest_path = path.join("manifest.bml");
let mut contents = String::new();
File::open(&manifest_path)
.and_then(|mut f| f.read_to_string(&mut contents))
.map_err(|e| ParsePresetError::IOError(path.to_path_buf(), e))?;
// BML expects a newline.
contents.push_str("\n");
let contents = contents.to_string();
Ok(bml::BmlNode::try_from(&*contents)?)
}
fn parse_values(node: &BmlNode) -> Result<Vec<Value>, ParsePresetError>{
let programs = node.named("program");
let program_len = programs.len();
let mut values = Vec::new();
for (index, programs) in programs.chain(node.named("output")).enumerate() {
if let Some(filter) = programs.named("filter").next() {
// NOPANIC: infallible
values.push(Value::FilterMode(index as i32, FilterMode::from_str(filter.value().trim()).unwrap()))
}
if let Some(vertex) = programs.named("vertex").next() {
values.push(Value::Shader(index as i32, ShaderType::Quark(ShaderStage::Vertex), PathBuf::from_str(vertex.value().trim())
.expect("Infallible")))
}
if let Some(fragment) = programs.named("fragment").next() {
values.push(Value::Shader(index as i32, ShaderType::Quark(ShaderStage::Fragment), PathBuf::from_str(fragment.value().trim())
.expect("Infallible")))
}
}
eprintln!("{values:?}");
Ok(values)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn parse_shader() {
let preset = parse_bml_node("../test/quark-shaders/CRT-Royale.shader").unwrap();
let values = parse_values(&preset);
for program in preset.named("program").chain(preset.named("output")) {
eprintln!("{:?}", program);
}
}
}

View file

@ -1,9 +0,0 @@
[package]
name = "librashader-quark"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
bml = "0.3.1"

View file

@ -1,40 +0,0 @@
use std::error::Error;
use std::fs::File;
use std::io::Read;
use std::path::Path;
use bml::BmlNode;
pub fn add(left: usize, right: usize) -> usize {
left + right
}
pub fn parse_preset(path: impl AsRef<Path>) -> Result<BmlNode, Box<dyn Error>> {
let path = path.as_ref();
let path = path
.canonicalize()?;
let mut manifest_path = path.join("manifest.bml");
let mut contents = String::new();
File::open(&manifest_path)
.and_then(|mut f| f.read_to_string(&mut contents))?;
// BML expects a newline.
contents.push_str("\n");
let contents = contents.to_string();
Ok(bml::BmlNode::try_from(&*contents)?)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn parse_shader() {
let preset = parse_preset("../test/quark-shaders/CRT-Royale.shader").unwrap();
for program in preset.named("program") {
eprintln!("{:?}", program);
}
}
}

View file

@ -6,7 +6,7 @@ use crate::reflect::semantics::{
Semantic, ShaderSemantics, TextureSemantics, UniformSemantic, UniqueSemantics,
};
use librashader_preprocess::{PreprocessError, ShaderSource};
use librashader_presets::{ShaderPassConfig, TextureConfig};
use librashader_presets::{ShaderPassConfig, ShaderPath, TextureConfig};
use rustc_hash::FxHashMap;
/// Artifacts of a reflected and compiled shader pass.
@ -83,7 +83,13 @@ where
let passes = passes
.into_iter()
.map(|shader| {
let source: ShaderSource = ShaderSource::load(&shader.name)?;
let source = match &shader.source_path {
ShaderPath::Slang(source_path) => ShaderSource::load(source_path)?,
ShaderPath::Quark { vertex, fragment } => {
panic!("quark shaders not implemented")
}
};
let compiled = C::compile(&source)?;
let reflect = T::from_compilation(compiled)?;

View file

@ -61,7 +61,7 @@ pub mod presets {
let iters: Result<Vec<Vec<ShaderParameter>>, PreprocessError> = preset
.shaders
.iter()
.map(|s| ShaderSource::load(&s.name).map(|s| s.parameters.into_values().collect()))
.map(|s| ShaderSource::load(&s.source_path).map(|s| s.parameters.into_values().collect()))
.collect();
let iters = iters?;
Ok(iters.into_iter().flatten())