Refactor the node macro and simply most of the node implementations (#1942)

* Add support structure for new node macro to gcore

* Fix compile issues and code generation

* Implement new node_fn macro

* Implement property translation

* Fix NodeIO type generation

* Start translating math nodes

* Move node implementation to outer scope to allow usage of local imports

* Add expose attribute to allow controlling the parameter exposure

* Add rust analyzer support for #[implementations] attribute

* Migrate logic nodes

* Handle where clause properly

* Implement argument ident pattern preservation

* Implement adjustment layer mapping

* Fix node registry types

* Fix module paths

* Improve demo artwork comptibility

* Improve macro error reporting

* Fix handling of impl node implementations

* Fix nodeio type computation

* Fix opacity node and graph type resolution

* Fix loading of demo artworks

* Fix eslint

* Fix typo in macro test

* Remove node definitions for Adjustment Nodes

* Fix type alias property generation and make adjustments footprint aware

* Convert vector nodes

* Implement path overrides

* Fix stroke node

* Fix painted dreams

* Implement experimental type level specialization

* Fix poisson disk sampling -> all demo artworks should work again

* Port text node + make node macro more robust by implementing lifetime substitution

* Fix vector node tests

* Fix red dress demo + ci

* Fix clippy warnings

* Code review

* Fix primary input issues

* Improve math nodes and audit others

* Set no_properties when no automatic properties are derived

* Port vector generator nodes (could not derive all definitions yet)

* Various QA changes and add min/max/mode_range to number parameters

* Add min and max for f64 and u32

* Convert gpu nodes and clean up unused nodes

* Partially port transform node

* Allow implementations on call arg

* Port path modify node

* Start porting graphic element nodes

* Transform nodes in graphic_element.rs

* Port brush node

* Port nodes in wasm_executior

* Rename node macro

* Fix formatting

* Fix Mandelbrot node

* Formatting

* Fix Load Image and Load Resource nodes, add scope input to node macro

* Remove unnecessary underscores

* Begin attemping to make nodes resolution-aware

* Infer a generic manual compositon type on generic call arg

* Various fixes and work towards merging

* Final changes for merge!

* Fix tests, probably

* More free line removals!

---------

Co-authored-by: Keavon Chambers <keavon@keavon.com>
This commit is contained in:
Dennis Kobert 2024-09-20 12:50:30 +02:00 committed by GitHub
parent ca0d102296
commit e352c7fa71
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
92 changed files with 4255 additions and 7275 deletions

View file

@ -788,7 +788,7 @@ pub struct Shader<'a> {
pub io: ShaderIO,
}
#[derive(Clone, Debug, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
#[derive(Clone, Debug, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize, dyn_any::DynAny)]
pub struct ShaderIO {
pub inputs: Vec<AbstractShaderInput>,
pub output: AbstractShaderInput,
@ -828,21 +828,13 @@ impl<T> ShaderInputNode<T> {
}
}
pub struct UniformNode<Executor> {
executor: Executor,
}
#[node_macro::node_fn(UniformNode)]
async fn uniform_node<'a: 'input, T: ToUniformBuffer + Send>(data: T, executor: &'a WgpuExecutor) -> WgpuShaderInput {
#[node_macro::node(category(""))]
async fn uniform<'a: 'n, T: ToUniformBuffer + Send + 'n>(_: (), #[implementations(f32, DAffine2)] data: T, executor: &'a WgpuExecutor) -> WgpuShaderInput {
executor.create_uniform_buffer(data).unwrap()
}
pub struct StorageNode<Executor> {
executor: Executor,
}
#[node_macro::node_fn(StorageNode)]
async fn storage_node<'a: 'input, T: ToStorageBuffer + Send>(data: T, executor: &'a WgpuExecutor) -> WgpuShaderInput {
#[node_macro::node(category(""))]
async fn storage<'a: 'n, T: ToStorageBuffer + Send + 'n>(_: (), #[implementations(Vec<u8>)] data: T, executor: &'a WgpuExecutor) -> WgpuShaderInput {
executor
.create_storage_buffer(
data,
@ -856,98 +848,57 @@ async fn storage_node<'a: 'input, T: ToStorageBuffer + Send>(data: T, executor:
.unwrap()
}
pub struct PushNode<Value> {
value: Value,
}
#[node_macro::node_fn(PushNode)]
async fn push_node<T: Send>(mut vec: Vec<T>, value: T) {
vec.push(value);
}
pub struct CreateOutputBufferNode<Executor, Ty> {
executor: Executor,
ty: Ty,
}
#[node_macro::node_fn(CreateOutputBufferNode)]
async fn create_output_buffer_node<'a: 'input>(size: usize, executor: &'a WgpuExecutor, ty: Type) -> Arc<WgpuShaderInput> {
#[node_macro::node(category(""))]
async fn create_output_buffer<'a: 'n>(_: (), size: usize, executor: &'a WgpuExecutor, ty: Type) -> Arc<WgpuShaderInput> {
Arc::new(executor.create_output_buffer(size, ty, true).unwrap())
}
pub struct CreateComputePassNode<Executor, Output, Instances> {
executor: Executor,
output: Output,
instances: Instances,
}
#[node_macro::node_fn(CreateComputePassNode)]
async fn create_compute_pass_node<'a: 'input>(layout: PipelineLayout, executor: &'a WgpuExecutor, output: WgpuShaderInput, instances: ComputePassDimensions) -> CommandBuffer {
#[node_macro::node(skip_impl)]
async fn create_compute_pass<'a: 'n>(_: (), layout: PipelineLayout, executor: &'a WgpuExecutor, output: WgpuShaderInput, instances: ComputePassDimensions) -> CommandBuffer {
executor.create_compute_pass(&layout, Some(output.into()), instances).unwrap()
}
pub struct CreatePipelineLayoutNode<EntryPoint, Bindgroup, OutputBuffer> {
entry_point: EntryPoint,
bind_group: Bindgroup,
output_buffer: OutputBuffer,
}
#[node_macro::node_fn(CreatePipelineLayoutNode)]
async fn create_pipeline_layout_node(shader: ShaderHandle, entry_point: String, bind_group: Bindgroup, output_buffer: Arc<WgpuShaderInput>) -> PipelineLayout {
#[node_macro::node(category("Debug: GPU"))]
async fn create_pipeline_layout(
_: (),
shader: impl Node<(), Output = ShaderHandle>,
entry_point: String,
bind_group: impl Node<(), Output = Bindgroup>,
output_buffer: Arc<WgpuShaderInput>,
) -> PipelineLayout {
PipelineLayout {
shader: shader.into(),
shader: shader.eval(()).await.into(),
entry_point,
bind_group: bind_group.into(),
bind_group: bind_group.eval(()).await.into(),
output_buffer,
}
}
pub struct ExecuteComputePipelineNode<Executor> {
executor: Executor,
}
#[node_macro::node_fn(ExecuteComputePipelineNode)]
async fn execute_compute_pipeline_node<'a: 'input>(encoder: CommandBuffer, executor: &'a WgpuExecutor) {
executor.execute_compute_pipeline(encoder).unwrap();
}
pub struct ReadOutputBufferNode<Executor, ComputePass> {
executor: Executor,
_compute_pass: ComputePass,
}
#[node_macro::node_fn(ReadOutputBufferNode)]
async fn read_output_buffer_node<'a: 'input>(buffer: Arc<WgpuShaderInput>, executor: &'a WgpuExecutor, _compute_pass: ()) -> Vec<u8> {
#[node_macro::node(category(""))]
async fn read_output_buffer<'a: 'n>(_: (), buffer: Arc<WgpuShaderInput>, executor: &'a WgpuExecutor, _compute_pass: ()) -> Vec<u8> {
executor.read_output_buffer(buffer).await.unwrap()
}
pub type WindowHandle = Arc<SurfaceHandle<Window>>;
pub struct CreateGpuSurfaceNode;
#[node_macro::node_fn(CreateGpuSurfaceNode)]
async fn create_gpu_surface<'a: 'input, Io: ApplicationIo<Executor = WgpuExecutor, Surface = Window> + 'a + Send + Sync>(editor_api: &'a EditorApi<Io>) -> Option<WgpuSurface> {
#[node_macro::node(skip_impl)]
fn create_gpu_surface<'a: 'n, Io: ApplicationIo<Executor = WgpuExecutor, Surface = Window> + 'a + Send + Sync>(_: (), editor_api: &'a EditorApi<Io>) -> Option<WgpuSurface> {
let canvas = editor_api.application_io.as_ref()?.window()?;
let executor = editor_api.application_io.as_ref()?.gpu_executor()?;
Some(Arc::new(executor.create_surface(canvas).ok()?))
}
pub struct RenderTextureNode<Image, Surface, EditorApi> {
image: Image,
surface: Surface,
executor: EditorApi,
}
#[derive(DynAny, Clone, Debug)]
pub struct ShaderInputFrame {
shader_input: Arc<WgpuShaderInput>,
transform: DAffine2,
}
#[node_macro::node_fn(RenderTextureNode)]
async fn render_texture_node<'a: 'input>(footprint: Footprint, image: impl Node<Footprint, Output = ShaderInputFrame>, surface: Option<WgpuSurface>, executor: &'a WgpuExecutor) -> SurfaceFrame {
#[node_macro::node(category(""))]
async fn render_texture<'a: 'n>(_: (), footprint: Footprint, image: impl Node<Footprint, Output = ShaderInputFrame>, surface: Option<WgpuSurface>, executor: &'a WgpuExecutor) -> SurfaceFrame {
let surface = surface.unwrap();
let surface_id = surface.window_id;
let image = self.image.eval(footprint).await;
let image = image.eval(footprint).await;
let transform = image.transform;
executor.create_render_pass(footprint, image, surface).unwrap();
@ -959,12 +910,8 @@ async fn render_texture_node<'a: 'input>(footprint: Footprint, image: impl Node<
}
}
pub struct UploadTextureNode<Executor> {
executor: Executor,
}
#[node_macro::node_fn(UploadTextureNode)]
async fn upload_texture<'a: 'input>(input: ImageFrame<Color>, executor: &'a WgpuExecutor) -> TextureFrame {
#[node_macro::node(category(""))]
async fn upload_texture<'a: 'n>(_: (), input: ImageFrame<Color>, executor: &'a WgpuExecutor) -> TextureFrame {
// let new_data: Vec<RGBA16F> = input.image.data.into_iter().map(|c| c.into()).collect();
let new_data = input.image.data.into_iter().map(SRGBA8::from).collect();
let new_image = Image {