Skip to content

Commit fa90210

Browse files
committed
shader-rt: initial
1 parent ee5d95a commit fa90210

10 files changed

Lines changed: 278 additions & 22 deletions

File tree

node-graph/gcore/src/raster_types.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ mod gpu {
137137

138138
#[derive(Clone, Debug, PartialEq, Hash)]
139139
pub struct GPU {
140-
texture: wgpu::Texture,
140+
pub texture: wgpu::Texture,
141141
}
142142

143143
impl Sealed for Raster<GPU> {}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
use glam::{Vec2, Vec4};
2+
use spirv_std::spirv;
3+
4+
/// webgpu NDC is like OpenGL: (-1.0 .. 1.0, -1.0 .. 1.0, 0.0 .. 1.0)
5+
/// https://www.w3.org/TR/webgpu/#coordinate-systems
6+
const FULLSCREEN_VERTICES: [Vec2; 3] = [Vec2::new(-1., -1.), Vec2::new(-1., 3.), Vec2::new(3., -1.)];
7+
8+
#[spirv(vertex)]
9+
pub fn fullscreen_vertex(#[spirv(vertex_index)] vertex_index: u32, #[spirv(position)] gl_position: &mut Vec4) {
10+
// broken on edition 2024 branch
11+
// let vertex = unsafe { *FULLSCREEN_VERTICES.index_unchecked(vertex_index as usize) };
12+
let vertex = FULLSCREEN_VERTICES[vertex_index as usize];
13+
*gl_position = Vec4::from((vertex, 0., 1.));
14+
}

node-graph/graster-nodes/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ pub mod adjustments;
66
pub mod black_and_white;
77
pub mod blending_nodes;
88
pub mod cubic_spline;
9+
pub mod fullscreen_vertex;
910

1011
#[cfg(feature = "std")]
1112
pub mod curve;

node-graph/node-macro/src/codegen.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -295,7 +295,12 @@ pub(crate) fn generate_node_code(parsed: &ParsedNodeFn) -> syn::Result<TokenStre
295295

296296
let cfg = crate::shader_nodes::modify_cfg(&attributes);
297297
let node_input_accessor = generate_node_input_references(parsed, fn_generics, &field_idents, &graphene_core, &identifier, &cfg);
298-
let shader_entry_point = attributes.shader_node.as_ref().map(|n| n.codegen_shader_entry_point(parsed)).unwrap_or(Ok(TokenStream::new()))?;
298+
let (shader_entry_point, shader_gpu_node) = attributes
299+
.shader_node
300+
.as_ref()
301+
.map::<syn::Result<_>, _>(|n| Ok((n.codegen_shader_entry_point(parsed)?, n.codegen_gpu_node(parsed)?)))
302+
.unwrap_or(Ok((TokenStream::new(), TokenStream::new())))?;
303+
299304
Ok(quote! {
300305
/// Underlying implementation for [#struct_name]
301306
#[inline]
@@ -386,6 +391,8 @@ pub(crate) fn generate_node_code(parsed: &ParsedNodeFn) -> syn::Result<TokenStre
386391
}
387392

388393
#shader_entry_point
394+
395+
#shader_gpu_node
389396
})
390397
}
391398

node-graph/node-macro/src/parsing.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ pub(crate) struct ParsedNodeFn {
3939
pub(crate) description: String,
4040
}
4141

42-
#[derive(Debug, Default)]
42+
#[derive(Debug, Default, Clone)]
4343
pub(crate) struct NodeFnAttributes {
4444
pub(crate) category: Option<LitStr>,
4545
pub(crate) display_name: Option<LitStr>,
@@ -604,14 +604,14 @@ fn parse_field(pat_ident: PatIdent, ty: Type, attrs: &[Attribute]) -> syn::Resul
604604
ty,
605605
value_source,
606606
implementations,
607+
gpu_image,
607608
}),
608609
name,
609610
description,
610611
widget_override,
611612
number_display_decimal_places,
612613
number_step,
613614
unit,
614-
gpu_image,
615615
})
616616
}
617617
}

node-graph/node-macro/src/shader_nodes/mod.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ pub fn modify_cfg(attributes: &NodeFnAttributes) -> TokenStream {
1919
}
2020
}
2121

22-
#[derive(Debug, VariantNames)]
22+
#[derive(Debug, Clone, VariantNames)]
2323
pub(crate) enum ShaderNodeType {
2424
PerPixelAdjust(PerPixelAdjust),
2525
}
@@ -36,6 +36,7 @@ impl Parse for ShaderNodeType {
3636

3737
pub trait CodegenShaderEntryPoint {
3838
fn codegen_shader_entry_point(&self, parsed: &ParsedNodeFn) -> syn::Result<TokenStream>;
39+
fn codegen_gpu_node(&self, parsed: &ParsedNodeFn) -> syn::Result<TokenStream>;
3940
}
4041

4142
impl CodegenShaderEntryPoint for ShaderNodeType {
@@ -48,4 +49,10 @@ impl CodegenShaderEntryPoint for ShaderNodeType {
4849
ShaderNodeType::PerPixelAdjust(x) => x.codegen_shader_entry_point(parsed),
4950
}
5051
}
52+
53+
fn codegen_gpu_node(&self, parsed: &ParsedNodeFn) -> syn::Result<TokenStream> {
54+
match self {
55+
ShaderNodeType::PerPixelAdjust(x) => x.codegen_gpu_node(parsed),
56+
}
57+
}
5158
}

node-graph/node-macro/src/shader_nodes/per_pixel_adjust.rs

Lines changed: 68 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
1-
use crate::parsing::{ParsedField, ParsedNodeFn};
1+
use crate::parsing::{Input, NodeFnAttributes, ParsedField, ParsedFieldType, ParsedNodeFn, RegularParsedField};
22
use crate::shader_nodes::CodegenShaderEntryPoint;
3+
use convert_case::{Case, Casing};
34
use proc_macro2::{Ident, TokenStream};
45
use quote::{ToTokens, format_ident, quote};
56
use std::borrow::Cow;
67
use syn::parse::{Parse, ParseStream};
8+
use syn::{Path, Type, TypePath};
79

8-
#[derive(Debug)]
10+
#[derive(Debug, Clone)]
911
pub struct PerPixelAdjust {}
1012

1113
impl Parse for PerPixelAdjust {
@@ -17,28 +19,31 @@ impl Parse for PerPixelAdjust {
1719
impl CodegenShaderEntryPoint for PerPixelAdjust {
1820
fn codegen_shader_entry_point(&self, parsed: &ParsedNodeFn) -> syn::Result<TokenStream> {
1921
let fn_name = &parsed.fn_name;
20-
let gpu_mod = format_ident!("{}_gpu", parsed.fn_name);
22+
let gpu_mod = format_ident!("{}_gpu_entry_point", parsed.fn_name);
2123
let spirv_image_ty = quote!(Image2d);
2224

2325
// bindings for images start at 1
2426
let mut binding_cnt = 0;
2527
let params = parsed
2628
.fields
2729
.iter()
28-
.map(|f| match f {
29-
ParsedField::Node { pat_ident, .. } => Err(syn::Error::new_spanned(pat_ident, "PerPixelAdjust shader nodes cannot accept other nodes as generics")),
30-
ParsedField::Regular { gpu_image: false, pat_ident, ty, .. } => Ok(Param {
31-
ident: Cow::Borrowed(&pat_ident.ident),
32-
ty: Cow::Owned(ty.to_token_stream()),
33-
param_type: ParamType::Uniform,
34-
}),
35-
ParsedField::Regular { gpu_image: true, pat_ident, .. } => {
36-
binding_cnt += 1;
37-
Ok(Param {
38-
ident: Cow::Owned(format_ident!("image_{}", &pat_ident.ident)),
39-
ty: Cow::Borrowed(&spirv_image_ty),
40-
param_type: ParamType::Image { binding: binding_cnt },
41-
})
30+
.map(|f| {
31+
let ident = &f.pat_ident;
32+
match &f.ty {
33+
ParsedFieldType::Node { .. } => Err(syn::Error::new_spanned(ident, "PerPixelAdjust shader nodes cannot accept other nodes as generics")),
34+
ParsedFieldType::Regular(RegularParsedField { gpu_image: false, ty, .. }) => Ok(Param {
35+
ident: Cow::Borrowed(&ident.ident),
36+
ty: Cow::Owned(ty.to_token_stream()),
37+
param_type: ParamType::Uniform,
38+
}),
39+
ParsedFieldType::Regular(RegularParsedField { gpu_image: true, .. }) => {
40+
binding_cnt += 1;
41+
Ok(Param {
42+
ident: Cow::Owned(format_ident!("image_{}", &ident.ident)),
43+
ty: Cow::Borrowed(&spirv_image_ty),
44+
param_type: ParamType::Image { binding: binding_cnt },
45+
})
46+
}
4247
}
4348
})
4449
.collect::<syn::Result<Vec<_>>>()?;
@@ -93,6 +98,52 @@ impl CodegenShaderEntryPoint for PerPixelAdjust {
9398
}
9499
})
95100
}
101+
102+
fn codegen_gpu_node(&self, parsed: &ParsedNodeFn) -> syn::Result<TokenStream> {
103+
let fn_name = format_ident!("{}_gpu", parsed.fn_name);
104+
let struct_name = format_ident!("{}", fn_name.to_string().to_case(Case::Pascal));
105+
let mod_name = fn_name.clone();
106+
107+
let fields = parsed
108+
.fields
109+
.iter()
110+
.map(|f| match &f.ty {
111+
ParsedFieldType::Regular(reg) => Ok(ParsedField {
112+
ty: ParsedFieldType::Regular(RegularParsedField { gpu_image: false, ..reg.clone() }),
113+
..f.clone()
114+
}),
115+
ParsedFieldType::Node { .. } => Err(syn::Error::new_spanned(&f.pat_ident, "PerPixelAdjust shader nodes cannot accept other nodes as generics")),
116+
})
117+
.collect::<syn::Result<_>>()?;
118+
let body = quote! {};
119+
120+
crate::codegen::generate_node_code(&ParsedNodeFn {
121+
vis: parsed.vis.clone(),
122+
attributes: NodeFnAttributes {
123+
shader_node: None,
124+
..parsed.attributes.clone()
125+
},
126+
fn_name,
127+
struct_name,
128+
mod_name,
129+
fn_generics: vec![],
130+
where_clause: None,
131+
input: Input {
132+
pat_ident: parsed.input.pat_ident.clone(),
133+
ty: Type::Path(TypePath {
134+
path: Path::from(format_ident!("Ctx")),
135+
qself: None,
136+
}),
137+
implementations: Default::default(),
138+
},
139+
output_type: parsed.output_type.clone(),
140+
is_async: true,
141+
fields,
142+
body,
143+
crate_name: parsed.crate_name.clone(),
144+
description: "".to_string(),
145+
})
146+
}
96147
}
97148

98149
struct Param<'a> {

node-graph/wgpu-executor/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
mod context;
2+
pub mod shader_runtime;
23
pub mod texture_upload;
34

45
use anyhow::Result;
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
use crate::Context;
2+
use crate::shader_runtime::per_pixel_adjust_runtime::PerPixelAdjustShaderRuntime;
3+
4+
pub mod per_pixel_adjust_runtime;
5+
6+
pub const FULLSCREEN_VERTEX_SHADER_NAME: &str = "fullscreen_vertexfullscreen_vertex";
7+
8+
pub struct ShaderRuntime {
9+
context: Context,
10+
per_pixel_adjust: PerPixelAdjustShaderRuntime,
11+
}
12+
13+
impl ShaderRuntime {
14+
pub fn new(context: &Context) -> Self {
15+
Self {
16+
context: context.clone(),
17+
per_pixel_adjust: PerPixelAdjustShaderRuntime::new(),
18+
}
19+
}
20+
}

0 commit comments

Comments
 (0)