mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-20 03:18:06 +08:00
Shaders: runtime and shader node codegen (#2985)
* shader-rt: initial * shader-rt: fix recursion when generating shader node * shader-rt: replace gpu node's args and ret types with `Raster<GPU>` * shader-rt: properly cfg out the gpu node * shader-rt: fix `impl Context` in the wrong places * shader-rt: disable gpu blend node, needs two images * shader-rt: connect shader runtime * shader-rt: pass WgpuExecutor by reference * shader-rt: correct bindings with derpy arg buffer * shader-rt: manual pipeline layout, fixing errors when bindings got DCE'd * shader-rt: correct RT format, working invert gpu node * shader-rt: cleanup codegen with common sym struct * shader-rt: correct arg buffer handling * shader-nodes feature: put shader nodes behind feature gate * shader-nodes feature: rename any `gpu_node` to `shader-node` * shaders-rt: fix wgpu label name * shaders-rt: explain fullscreen_vertex coordinates with a drawing
This commit is contained in:
@@ -3,24 +3,38 @@ use crate::shader_nodes::per_pixel_adjust::PerPixelAdjust;
|
||||
use proc_macro2::{Ident, TokenStream};
|
||||
use quote::quote;
|
||||
use strum::VariantNames;
|
||||
use syn::Error;
|
||||
use syn::parse::{Parse, ParseStream};
|
||||
use syn::punctuated::Punctuated;
|
||||
use syn::{Error, Token};
|
||||
|
||||
pub mod per_pixel_adjust;
|
||||
|
||||
pub const STD_FEATURE_GATE: &str = "std";
|
||||
pub const SHADER_NODES_FEATURE_GATE: &str = "shader-nodes";
|
||||
|
||||
pub fn modify_cfg(attributes: &NodeFnAttributes) -> TokenStream {
|
||||
match (&attributes.cfg, &attributes.shader_node) {
|
||||
(Some(cfg), Some(_)) => quote!(#[cfg(all(#cfg, feature = #STD_FEATURE_GATE))]),
|
||||
(Some(cfg), None) => quote!(#[cfg(#cfg)]),
|
||||
(None, Some(_)) => quote!(#[cfg(feature = #STD_FEATURE_GATE)]),
|
||||
(None, None) => quote!(),
|
||||
}
|
||||
let feature_gate = match &attributes.shader_node {
|
||||
// shader node cfg is done on the mod
|
||||
Some(ShaderNodeType::ShaderNode) => quote!(),
|
||||
Some(_) => quote!(feature = #STD_FEATURE_GATE),
|
||||
None => quote!(),
|
||||
};
|
||||
let cfgs: Punctuated<_, Token![,]> = match &attributes.cfg {
|
||||
None => [&feature_gate].into_iter().collect(),
|
||||
Some(cfg) => [cfg, &feature_gate].into_iter().collect(),
|
||||
};
|
||||
quote!(#[cfg(all(#cfgs))])
|
||||
}
|
||||
|
||||
#[derive(Debug, VariantNames)]
|
||||
#[derive(Debug, Clone, VariantNames)]
|
||||
pub(crate) enum ShaderNodeType {
|
||||
/// Marker for this node being in a gpu node crate, but not having a gpu implementation. This is distinct from not
|
||||
/// declaring `shader_node` at all, as it will wrap the CPU node with a `#[cfg(feature = "std")]` feature gate.
|
||||
None,
|
||||
/// Marker for this node being a generated gpu node implementation, that should not emit anything to prevent
|
||||
/// recursively generating more gpu nodes. But it still counts as a gpu node and will get the
|
||||
/// `#[cfg(feature = "std")]` feature gate around it's impl.
|
||||
ShaderNode,
|
||||
PerPixelAdjust(PerPixelAdjust),
|
||||
}
|
||||
|
||||
@@ -28,24 +42,37 @@ impl Parse for ShaderNodeType {
|
||||
fn parse(input: ParseStream) -> syn::Result<Self> {
|
||||
let ident: Ident = input.parse()?;
|
||||
Ok(match ident.to_string().as_str() {
|
||||
"None" => ShaderNodeType::None,
|
||||
"PerPixelAdjust" => ShaderNodeType::PerPixelAdjust(PerPixelAdjust::parse(input)?),
|
||||
_ => return Err(Error::new_spanned(&ident, format!("attr 'shader_node' must be one of {:?}", Self::VARIANTS))),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub trait CodegenShaderEntryPoint {
|
||||
fn codegen_shader_entry_point(&self, parsed: &ParsedNodeFn) -> syn::Result<TokenStream>;
|
||||
pub trait ShaderCodegen {
|
||||
fn codegen(&self, parsed: &ParsedNodeFn) -> syn::Result<ShaderTokens>;
|
||||
}
|
||||
|
||||
impl CodegenShaderEntryPoint for ShaderNodeType {
|
||||
fn codegen_shader_entry_point(&self, parsed: &ParsedNodeFn) -> syn::Result<TokenStream> {
|
||||
if parsed.is_async {
|
||||
return Err(Error::new_spanned(&parsed.fn_name, "Shader nodes must not be async"));
|
||||
impl ShaderCodegen for ShaderNodeType {
|
||||
fn codegen(&self, parsed: &ParsedNodeFn) -> syn::Result<ShaderTokens> {
|
||||
match self {
|
||||
ShaderNodeType::None | ShaderNodeType::ShaderNode => (),
|
||||
_ => {
|
||||
if parsed.is_async {
|
||||
return Err(Error::new_spanned(&parsed.fn_name, "Shader nodes must not be async"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
match self {
|
||||
ShaderNodeType::PerPixelAdjust(x) => x.codegen_shader_entry_point(parsed),
|
||||
ShaderNodeType::None | ShaderNodeType::ShaderNode => Ok(ShaderTokens::default()),
|
||||
ShaderNodeType::PerPixelAdjust(x) => x.codegen(parsed),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Default)]
|
||||
pub struct ShaderTokens {
|
||||
pub shader_entry_point: TokenStream,
|
||||
pub gpu_node: TokenStream,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user