Lay groundwork for directly rendering to the canvas without a cpu roundrip (#1291)

* Add Texture handle type

* Add Texture View to shader inputs

* Implement basic rendering pipeline

* Render first texture using render pipeline

* Fix output color space

* Precompute the rendering pipeline

* Move gpu context creation to editor api

* Port gpu-executor nodes to node registry

* Fix canvas nodes and make code compile for non wasm targets

* Pin wasm-bindgen version

* Disable miri temoporarily for better ci times

* Fix formatting

* Remove unsafe block

* Bump wasm-pack version

* Bump wasm-bindgen version

* Add gpu feature guard for push node

* Make Into node async
This commit is contained in:
Dennis Kobert 2023-06-07 17:13:21 +02:00 committed by Keavon Chambers
parent 0c93a62d55
commit 45b04f4eb9
33 changed files with 1574 additions and 339 deletions

View file

@ -16,6 +16,8 @@ quantization = ["graphene-std/quantization"]
graphene-core = { path = "../gcore", features = ["async", "std"] }
graphene-std = { path = "../gstd" }
graph-craft = { path = "../graph-craft" }
gpu-executor = { path = "../gpu-executor" }
wgpu-executor = { path = "../wgpu-executor" }
dyn-any = { path = "../../libraries/dyn-any", features = [
"log-bad-types",
"glam",

View file

@ -8,15 +8,19 @@ use graphene_core::structural::Then;
use graphene_core::value::{ClonedNode, CopiedNode, ValueNode};
use graphene_core::vector::brush_stroke::BrushStroke;
use graphene_core::vector::VectorData;
use graphene_core::wasm_application_io::WasmSurfaceHandle;
use graphene_core::wasm_application_io::*;
use graphene_core::{application_io::SurfaceHandle, SurfaceFrame, WasmSurfaceHandleFrame};
use graphene_core::{concrete, generic};
use graphene_core::{fn_type, raster::*};
use graphene_core::{Cow, NodeIdentifier, Type, TypeDescriptor};
use graphene_core::{Node, NodeIO, NodeIOTypes};
use graphene_std::any::{ComposeTypeErased, DowncastBothNode, DynAnyNode, FutureWrapperNode, IntoTypeErasedNode};
use graphene_std::wasm_application_io::*;
#[cfg(feature = "gpu")]
use gpu_executor::{GpuExecutor, ShaderInput, ShaderInputFrame};
use graphene_std::raster::*;
use graphene_std::wasm_application_io::WasmEditorApi;
use wgpu_executor::WgpuExecutor;
use dyn_any::StaticType;
use glam::{DAffine2, DVec2};
@ -79,7 +83,7 @@ macro_rules! async_node {
args.reverse();
let node = <$path>::new($(graphene_std::any::input_node::<$type>(args.pop().expect("Not enough arguments provided to construct node"))),*);
let any: DynAnyNode<$input, _, _> = graphene_std::any::DynAnyNode::new(graphene_core::value::ValueNode::new(node));
any.into_type_erased()
Box::new(any) as TypeErasedBox
})
},
{
@ -181,7 +185,7 @@ fn node_registry() -> HashMap<NodeIdentifier, HashMap<NodeIOTypes, NodeConstruct
register_node!(graphene_core::ops::AddNode, input: (u32, u32), params: []),
register_node!(graphene_core::ops::AddNode, input: (u32, &u32), params: []),
register_node!(graphene_core::ops::CloneNode<_>, input: &ImageFrame<Color>, params: []),
register_node!(graphene_core::ops::CloneNode<_>, input: &graphene_core::EditorApi, params: []),
register_node!(graphene_core::ops::CloneNode<_>, input: &WasmEditorApi, params: []),
register_node!(graphene_core::ops::AddParameterNode<_>, input: u32, params: [u32]),
register_node!(graphene_core::ops::AddParameterNode<_>, input: &u32, params: [u32]),
register_node!(graphene_core::ops::AddParameterNode<_>, input: u32, params: [&u32]),
@ -190,9 +194,11 @@ fn node_registry() -> HashMap<NodeIdentifier, HashMap<NodeIOTypes, NodeConstruct
register_node!(graphene_core::ops::AddParameterNode<_>, input: &f64, params: [f64]),
register_node!(graphene_core::ops::AddParameterNode<_>, input: f64, params: [&f64]),
register_node!(graphene_core::ops::AddParameterNode<_>, input: &f64, params: [&f64]),
register_node!(graphene_core::ops::SomeNode, input: graphene_core::EditorApi, params: []),
register_node!(graphene_core::ops::IntoNode<_, ImageFrame<SRGBA8>>, input: ImageFrame<Color>, params: []),
register_node!(graphene_core::ops::IntoNode<_, ImageFrame<Color>>, input: ImageFrame<SRGBA8>, params: []),
register_node!(graphene_core::ops::SomeNode, input: WasmEditorApi, params: []),
async_node!(graphene_core::ops::IntoNode<_, ImageFrame<SRGBA8>>, input: ImageFrame<Color>, output: ImageFrame<SRGBA8>, params: []),
async_node!(graphene_core::ops::IntoNode<_, ImageFrame<Color>>, input: ImageFrame<SRGBA8>, output: ImageFrame<Color>, params: []),
#[cfg(feature = "gpu")]
async_node!(graphene_core::ops::IntoNode<_, &WgpuExecutor>, input: WasmEditorApi, output: &WgpuExecutor, params: []),
register_node!(graphene_std::raster::DownresNode<_>, input: ImageFrame<Color>, params: []),
register_node!(graphene_std::raster::MaskImageNode<_, _, _>, input: ImageFrame<Color>, params: [ImageFrame<Color>]),
register_node!(graphene_std::raster::MaskImageNode<_, _, _>, input: ImageFrame<Color>, params: [ImageFrame<Luma>]),
@ -244,26 +250,68 @@ fn node_registry() -> HashMap<NodeIdentifier, HashMap<NodeIOTypes, NodeConstruct
register_node!(graphene_std::raster::EmptyImageNode<_, _>, input: DAffine2, params: [Color]),
register_node!(graphene_core::memo::MonitorNode<_>, input: ImageFrame<Color>, params: []),
register_node!(graphene_core::memo::MonitorNode<_>, input: graphene_core::GraphicGroup, params: []),
register_node!(graphene_core::wasm_application_io::CreateSurfaceNode, input: graphene_core::EditorApi, params: []),
async_node!(graphene_std::wasm_application_io::CreateSurfaceNode, input: WasmEditorApi, output: Arc<SurfaceHandle<<graphene_std::wasm_application_io::WasmApplicationIo as graphene_core::application_io::ApplicationIo>::Surface>>, params: []),
async_node!(
graphene_core::wasm_application_io::DrawImageFrameNode<_>,
graphene_std::wasm_application_io::DrawImageFrameNode<_>,
input: ImageFrame<SRGBA8>,
output: WasmSurfaceHandleFrame,
params: [Arc<WasmSurfaceHandle>]
),
#[cfg(feature = "gpu")]
async_node!(gpu_executor::UniformNode<_>, input: f32, output: ShaderInput<WgpuExecutor>, params: [&WgpuExecutor]),
#[cfg(feature = "gpu")]
async_node!(gpu_executor::StorageNode<_>, input: Vec<u8>, output: ShaderInput<WgpuExecutor>, params: [&WgpuExecutor]),
#[cfg(feature = "gpu")]
async_node!(
gpu_executor::PushNode<_>,
input: Vec<ShaderInput<WgpuExecutor>>,
output: Vec<ShaderInput<WgpuExecutor>>,
params: [ShaderInput<WgpuExecutor>]
),
#[cfg(feature = "gpu")]
async_node!(gpu_executor::CreateOutputBufferNode<_, _>, input: usize, output: gpu_executor::ShaderInput<WgpuExecutor>, params: [&WgpuExecutor, Type]),
#[cfg(feature = "gpu")]
async_node!(gpu_executor::CreateComputePassNode<_, _, _>, input: gpu_executor::PipelineLayout<WgpuExecutor>, output: <WgpuExecutor as GpuExecutor>::CommandBuffer, params: [&WgpuExecutor, ShaderInput<WgpuExecutor>, gpu_executor::ComputePassDimensions]),
#[cfg(feature = "gpu")]
async_node!(gpu_executor::CreatePipelineLayoutNode<_, _, _, _>, input: <WgpuExecutor as GpuExecutor>::ShaderHandle, output: gpu_executor::PipelineLayout<WgpuExecutor>, params: [String, gpu_executor::Bindgroup<WgpuExecutor>, Arc<ShaderInput<WgpuExecutor>>]),
#[cfg(feature = "gpu")]
async_node!(
gpu_executor::ExecuteComputePipelineNode<_>,
input: <WgpuExecutor as GpuExecutor>::CommandBuffer,
output: (),
params: [&WgpuExecutor]
),
#[cfg(feature = "gpu")]
async_node!(gpu_executor::ReadOutputBufferNode<_, _>, input: Arc<ShaderInput<WgpuExecutor>>, output: Vec<u8>, params: [&WgpuExecutor, ()]),
#[cfg(all(feature = "gpu", target_arch = "wasm32"))]
async_node!(gpu_executor::CreateGpuSurfaceNode, input: WasmEditorApi, output: Arc<SurfaceHandle<<WgpuExecutor as GpuExecutor>::Surface>>, params: []),
#[cfg(feature = "gpu")]
async_node!(gpu_executor::RenderTextureNode<_, _>, input: ShaderInputFrame<WgpuExecutor>, output: SurfaceFrame, params: [Arc<SurfaceHandle<<WgpuExecutor as GpuExecutor>::Surface>>, &WgpuExecutor]),
#[cfg(feature = "gpu")]
async_node!(
gpu_executor::UploadTextureNode<_>,
input: ImageFrame<Color>,
output: ShaderInputFrame<WgpuExecutor>,
params: [&WgpuExecutor]
),
#[cfg(feature = "gpu")]
vec![(
NodeIdentifier::new("graphene_std::executor::MapGpuSingleImageNode<_>"),
|args| {
Box::pin(async move {
let document_node: DowncastBothNode<(), graph_craft::document::DocumentNode> = DowncastBothNode::new(args[0].clone());
let editor_api: DowncastBothNode<(), WasmEditorApi> = DowncastBothNode::new(args[1].clone());
//let document_node = ClonedNode::new(document_node.eval(()));
let node = graphene_std::executor::MapGpuNode::new(document_node);
let node = graphene_std::gpu_nodes::MapGpuNode::new(document_node, editor_api);
let any: DynAnyNode<ImageFrame<Color>, _, _> = graphene_std::any::DynAnyNode::new(graphene_core::value::ValueNode::new(node));
any.into_type_erased()
})
},
NodeIOTypes::new(concrete!(ImageFrame<Color>), concrete!(ImageFrame<Color>), vec![fn_type!(graph_craft::document::DocumentNode)]),
NodeIOTypes::new(
concrete!(ImageFrame<Color>),
concrete!(SurfaceFrame),
vec![fn_type!(graph_craft::document::DocumentNode), fn_type!(WasmEditorApi)],
),
)],
#[cfg(feature = "gpu")]
vec![(
@ -273,7 +321,7 @@ fn node_registry() -> HashMap<NodeIdentifier, HashMap<NodeIOTypes, NodeConstruct
let background: DowncastBothNode<(), ImageFrame<Color>> = DowncastBothNode::new(args[0].clone());
let blend_mode: DowncastBothNode<(), BlendMode> = DowncastBothNode::new(args[1].clone());
let opacity: DowncastBothNode<(), f32> = DowncastBothNode::new(args[2].clone());
let node = graphene_std::executor::BlendGpuImageNode::new(background, blend_mode, opacity);
let node = graphene_std::gpu_nodes::BlendGpuImageNode::new(background, blend_mode, opacity);
let any: DynAnyNode<ImageFrame<Color>, _, _> = graphene_std::any::DynAnyNode::new(graphene_core::value::ValueNode::new(node));
any.into_type_erased()
@ -374,47 +422,39 @@ fn node_registry() -> HashMap<NodeIdentifier, HashMap<NodeIOTypes, NodeConstruct
raster_node!(graphene_core::raster::PosterizeNode<_>, params: [f64]),
raster_node!(graphene_core::raster::ExposureNode<_, _, _>, params: [f64, f64, f64]),
register_node!(graphene_core::memo::LetNode<_>, input: Option<ImageFrame<Color>>, params: []),
register_node!(graphene_core::memo::LetNode<_>, input: Option<graphene_core::EditorApi>, params: []),
register_node!(graphene_core::memo::LetNode<_>, input: Option<WasmEditorApi>, params: []),
async_node!(graphene_core::memo::EndLetNode<_>, input: WasmEditorApi, output: ImageFrame<Color>, params: [ImageFrame<Color>]),
async_node!(graphene_core::memo::EndLetNode<_>, input: WasmEditorApi, output: VectorData, params: [VectorData]),
async_node!(
graphene_core::memo::EndLetNode<_>,
input: graphene_core::EditorApi,
output: ImageFrame<Color>,
params: [ImageFrame<Color>]
),
async_node!(graphene_core::memo::EndLetNode<_>, input: graphene_core::EditorApi, output: VectorData, params: [VectorData]),
async_node!(
graphene_core::memo::EndLetNode<_>,
input: graphene_core::EditorApi,
input: WasmEditorApi,
output: graphene_core::GraphicGroup,
params: [graphene_core::GraphicGroup]
),
async_node!(
graphene_core::memo::EndLetNode<_>,
input: graphene_core::EditorApi,
input: WasmEditorApi,
output: graphene_core::Artboard,
params: [graphene_core::Artboard]
),
async_node!(
graphene_core::memo::EndLetNode<_>,
input: graphene_core::EditorApi,
input: WasmEditorApi,
output: WasmSurfaceHandleFrame,
params: [WasmSurfaceHandleFrame]
),
async_node!(graphene_core::memo::EndLetNode<_>, input: WasmEditorApi, output: SurfaceFrame, params: [SurfaceFrame]),
vec![(
NodeIdentifier::new("graphene_core::memo::RefNode<_, _>"),
|args| {
Box::pin(async move {
let node: DowncastBothNode<Option<graphene_core::EditorApi>, graphene_core::EditorApi> = graphene_std::any::DowncastBothNode::new(args[0].clone());
let node: DowncastBothNode<Option<WasmEditorApi>, WasmEditorApi> = graphene_std::any::DowncastBothNode::new(args[0].clone());
let node = <graphene_core::memo::RefNode<_, _>>::new(node);
let any: DynAnyNode<(), _, _> = graphene_std::any::DynAnyNode::new(graphene_core::value::ValueNode::new(node));
any.into_type_erased()
})
},
NodeIOTypes::new(
concrete!(()),
concrete!(graphene_core::EditorApi),
vec![fn_type!(Option<graphene_core::EditorApi>, graphene_core::EditorApi)],
),
NodeIOTypes::new(concrete!(()), concrete!(WasmEditorApi), vec![fn_type!(Option<WasmEditorApi>, WasmEditorApi)]),
)],
async_node!(graphene_core::memo::MemoNode<_, _>, input: (), output: Image<Color>, params: [Image<Color>]),
async_node!(graphene_core::memo::MemoNode<_, _>, input: (), output: ImageFrame<Color>, params: [ImageFrame<Color>]),
@ -443,9 +483,9 @@ fn node_registry() -> HashMap<NodeIdentifier, HashMap<NodeIOTypes, NodeConstruct
input: Vec<graphene_core::vector::bezier_rs::Subpath<graphene_core::uuid::ManipulatorGroupId>>,
params: [Vec<graphene_core::uuid::ManipulatorGroupId>]
),
register_node!(graphene_core::text::TextGenerator<_, _, _>, input: graphene_core::EditorApi, params: [String, graphene_core::text::Font, f64]),
register_node!(graphene_core::text::TextGenerator<_, _, _>, input: WasmEditorApi, params: [String, graphene_core::text::Font, f64]),
register_node!(graphene_std::brush::VectorPointsNode, input: VectorData, params: []),
register_node!(graphene_core::ExtractImageFrame, input: graphene_core::EditorApi, params: []),
register_node!(graphene_core::ExtractImageFrame, input: WasmEditorApi, params: []),
register_node!(graphene_core::ConstructLayerNode<_, _, _, _, _, _, _>, input: graphene_core::vector::VectorData, params: [String, BlendMode, f32, bool, bool, bool, graphene_core::GraphicGroup]),
register_node!(graphene_core::ConstructLayerNode<_, _, _, _, _, _, _>, input: ImageFrame<Color>, params: [String, BlendMode, f32, bool, bool, bool, graphene_core::GraphicGroup]),
register_node!(graphene_core::ConstructLayerNode<_, _, _, _, _, _, _>, input: graphene_core::GraphicGroup, params: [String, BlendMode, f32, bool, bool, bool, graphene_core::GraphicGroup]),