Trick Cargo into adding shader files as dependencies
Add the context of the shader sources with include_bytes!() so that Cargo will recompile the rust source if the shader source changes.
This commit is contained in:
parent
77755b3eb5
commit
7f7b5261d2
47
src/lib.rs
47
src/lib.rs
|
|
@ -3,26 +3,26 @@
|
|||
use {
|
||||
naga::front::wgsl,
|
||||
proc_macro::TokenStream,
|
||||
quote::quote,
|
||||
std::fs,
|
||||
quote::{format_ident, quote},
|
||||
syn::{parse, LitStr},
|
||||
};
|
||||
|
||||
mod source_reader;
|
||||
|
||||
struct ShaderModule {
|
||||
source_text: String,
|
||||
source_file: source_reader::SourceFile,
|
||||
naga_module: naga::Module,
|
||||
}
|
||||
|
||||
impl ShaderModule {
|
||||
fn try_new(source_file: impl Into<std::path::PathBuf>) -> Result<Self, Error> {
|
||||
let source_filename = source_file.into();
|
||||
let source_file = source_reader::read_source_file(source_filename)?;
|
||||
let source_text = source_file.full_text().to_string();
|
||||
fn try_new(
|
||||
source_dir: &std::path::Path,
|
||||
source_filename: &std::path::Path,
|
||||
) -> Result<Self, Error> {
|
||||
let source_file = source_reader::read_source_file(source_dir, source_filename)?;
|
||||
|
||||
let naga_module = wgsl::parse_str(&source_text).map_err(|err| {
|
||||
if let Some(location) = err.location(&source_text) {
|
||||
let naga_module = wgsl::parse_str(&source_file.full_text()).map_err(|err| {
|
||||
if let Some(location) = err.location(&source_file.full_text()) {
|
||||
let (inner_source_filename, inner_line_num) =
|
||||
source_file.map_source_line_num(location.line_number as usize);
|
||||
Error::Message(format!(
|
||||
|
|
@ -41,26 +41,44 @@ impl ShaderModule {
|
|||
}
|
||||
})?;
|
||||
Ok(Self {
|
||||
source_text,
|
||||
source_file,
|
||||
naga_module,
|
||||
})
|
||||
}
|
||||
|
||||
fn emit_rust_code(&self) -> TokenStream {
|
||||
let source_text = &self.source_text;
|
||||
// We include the text of all the source files into the generated code
|
||||
// with include_bytes!() so that Cargo recognizes them as
|
||||
// dependencies. It's not pretty but it works. Since the file contents
|
||||
// are just stored in unused local variables, they should be removed by
|
||||
// the optimizer and not affect the compiled code.
|
||||
let source_text = &self.source_file.full_text();
|
||||
let dependencies: Vec<_> = self
|
||||
.source_file
|
||||
.all_filenames()
|
||||
.iter()
|
||||
.map(|path| path.as_os_str().to_string_lossy())
|
||||
.collect();
|
||||
let dummy_var: Vec<_> = (0u32..)
|
||||
.map(|n| format_ident!("_{}", n))
|
||||
.take(dependencies.len())
|
||||
.collect();
|
||||
quote! {
|
||||
{
|
||||
#(let #dummy_var = include_bytes!(#dependencies);)*
|
||||
wgpu::ShaderModuleDescriptor {
|
||||
label: None,
|
||||
source: wgpu::ShaderSource::Wgsl(Cow::Borrowed(#source_text)),
|
||||
}
|
||||
}
|
||||
}
|
||||
.into()
|
||||
}
|
||||
}
|
||||
|
||||
struct WgslModuleMacroInput {
|
||||
source_dir: std::path::PathBuf,
|
||||
filename: String,
|
||||
filename: std::path::PathBuf,
|
||||
}
|
||||
|
||||
enum Error {
|
||||
|
|
@ -89,7 +107,7 @@ fn parse_input(token_stream: TokenStream) -> Result<WgslModuleMacroInput, Error>
|
|||
|
||||
let source_dir = token.span().source_file().path().parent().unwrap().into();
|
||||
let literal: LitStr = parse(token_stream)?;
|
||||
let filename = literal.value();
|
||||
let filename = std::path::Path::new(&literal.value()).into();
|
||||
Ok(WgslModuleMacroInput {
|
||||
source_dir,
|
||||
filename,
|
||||
|
|
@ -98,8 +116,7 @@ fn parse_input(token_stream: TokenStream) -> Result<WgslModuleMacroInput, Error>
|
|||
|
||||
fn wgsl_module_inner(input_token_stream: TokenStream) -> Result<TokenStream, Error> {
|
||||
let input = parse_input(input_token_stream)?;
|
||||
let full_filename = input.source_dir.join(&input.filename);
|
||||
let module = ShaderModule::try_new(full_filename)?;
|
||||
let module = ShaderModule::try_new(&input.source_dir, &input.filename)?;
|
||||
Ok(module.emit_rust_code())
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -29,10 +29,14 @@ impl SourceFile {
|
|||
pub fn map_source_line_num(&self, line_num: usize) -> (&Path, usize) {
|
||||
(&self.source_map.filename, line_num)
|
||||
}
|
||||
|
||||
pub fn all_filenames(&self) -> Vec<&Path> {
|
||||
vec![&self.source_map.filename]
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read_source_file(filename: PathBuf) -> Result<SourceFile, Error> {
|
||||
let source_text = fs::read_to_string(&filename).map_err(|err| {
|
||||
pub fn read_source_file(source_dir: &Path, filename: &Path) -> Result<SourceFile, Error> {
|
||||
let source_text = fs::read_to_string(&source_dir.join(filename)).map_err(|err| {
|
||||
Error::from_message(format!(
|
||||
"Could not open \"{}\": {}",
|
||||
&filename.as_os_str().to_string_lossy(),
|
||||
|
|
@ -42,7 +46,7 @@ pub fn read_source_file(filename: PathBuf) -> Result<SourceFile, Error> {
|
|||
Ok(SourceFile {
|
||||
source_text,
|
||||
source_map: SourceMap {
|
||||
filename,
|
||||
filename: filename.into(),
|
||||
offset: 0,
|
||||
total_lines: 0,
|
||||
insertions: vec![],
|
||||
|
|
|
|||
Loading…
Reference in New Issue