Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -481,7 +481,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
description: Cow::Borrowed("Loads an image from a given URL"),
properties: None,
},
#[cfg(all(feature = "gpu", target_family = "wasm"))]
#[cfg(feature = "gpu")]
DocumentNodeDefinition {
identifier: "Rasterize",
category: "Raster",
Expand All @@ -502,7 +502,10 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
..Default::default()
},
DocumentNode {
#[cfg(target_family = "wasm")]
inputs: vec![NodeInput::import(generic!(T), 0), NodeInput::import(concrete!(Footprint), 1), NodeInput::node(NodeId(1), 0)],
#[cfg(not(target_family = "wasm"))]
inputs: vec![NodeInput::import(generic!(T), 0), NodeInput::import(concrete!(Footprint), 1), NodeInput::scope("wgpu-executor")],
implementation: DocumentNodeImplementation::ProtoNode(wasm_application_io::rasterize::IDENTIFIER),
..Default::default()
},
Expand Down
75 changes: 70 additions & 5 deletions node-graph/gstd/src/wasm_application_io.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,19 @@ use base64::Engine;
pub use graph_craft::document::value::RenderOutputType;
pub use graph_craft::wasm_application_io::*;
use graphene_application_io::ApplicationIo;
#[cfg(target_family = "wasm")]
use graphene_core::gradient::GradientStops;
#[cfg(target_family = "wasm")]
use graphene_core::math::bbox::Bbox;
use graphene_core::raster::image::Image;
use graphene_core::raster_types::{CPU, Raster};
use graphene_core::table::Table;
#[cfg(target_family = "wasm")]
use graphene_core::transform::Footprint;
#[cfg(target_family = "wasm")]
use graphene_core::vector::Vector;
use graphene_core::{Color, Ctx};
#[cfg(target_family = "wasm")]
use graphene_core::{Graphic, WasmNotSend};
use graphene_svg_renderer::Render;
#[cfg(target_family = "wasm")]
use graphene_svg_renderer::{Render, RenderParams, RenderSvgSegmentList, SvgRender};
use graphene_svg_renderer::{RenderParams, RenderSvgSegmentList, SvgRender};
use std::sync::Arc;
#[cfg(target_family = "wasm")]
use wasm_bindgen::JsCast;
Expand Down Expand Up @@ -209,3 +206,71 @@ where
..Default::default()
})
}

#[cfg(not(target_family = "wasm"))]
#[node_macro::node(category(""))]
async fn rasterize<'a: 'n, T: WasmNotSend + 'n>(
_: impl Ctx,
#[implementations(
Table<Vector>,
Table<Raster<CPU>>,
Table<Graphic>,
Table<Color>,
Table<GradientStops>,
)]
mut data: Table<T>,
footprint: Footprint,
wgpu_executor: &'a wgpu_executor::WgpuExecutor,
) -> Table<Raster<CPU>>
where
Table<T>: graphene_svg_renderer::Render,
{
use graphene_core::math::bbox::Bbox;
use graphene_core::table::TableRow;
use wgpu_executor::RenderContext;

if footprint.transform.matrix2.determinant() == 0. {
log::trace!("Invalid footprint received for rasterization");
return Table::new();
}

let aabb = Bbox::from_transform(footprint.transform).to_axis_aligned_bbox();
let resolution = footprint.resolution;

// Adjust data transforms to account for bounding box offset
for row in data.iter_mut() {
*row.transform = glam::DAffine2::from_translation(-aabb.start) * *row.transform;
}

// Create Vello scene and render context
let mut scene = vello::Scene::new();
let mut context = RenderContext::default();

// Render data to Vello scene
let render_params = graphene_svg_renderer::RenderParams {
footprint: Footprint::default(),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't this included in ..Default::default()?

for_export: true,
..Default::default()
};
data.render_to_vello(&mut scene, Default::default(), &mut context, &render_params);

// Render scene to texture
let background = graphene_core::Color::TRANSPARENT;
let wgpu_texture = wgpu_executor
.render_vello_scene_to_texture(&scene, resolution, &context, background)
.await
.expect("Failed to render Vello scene to texture");

// Wrap the texture in a Raster<GPU>
let gpu_raster = Raster::new_gpu(wgpu_texture);

// Convert GPU raster to CPU raster using Convert trait
use graphene_core::ops::Convert;
let cpu_raster = gpu_raster.convert(Footprint::default(), wgpu_executor).await;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why don't we return a GPU texture here? Vector -> Rasterize -> Invert GPU and similar usecases.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wanted this to match the CPU version also to make this usable for the led artwork

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But we should make the two nodes compatible with each other so opening a document created in web also works on desktop

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we make two nodes one with CPU and one with GPU output, both using the same utility function to render?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd rather wait until we have proper automatic type conversion, this should ideally not be complexity we expose to the user, if we can avoid it

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We already do with all the oder GPU nodes

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Which is something I want to fix asap


Table::new_from_row(TableRow {
element: cpu_raster,
transform: footprint.transform,
..Default::default()
})
}
4 changes: 4 additions & 0 deletions node-graph/interpreted-executor/src/node_registry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,8 @@ fn node_registry() -> HashMap<ProtoNodeIdentifier, HashMap<NodeIOTypes, NodeCons
async_node!(graphene_core::context_modification::ContextModificationNode<_, _>, input: Context, fn_params: [Context => WgpuSurface, Context => graphene_std::ContextFeatures]),
async_node!(graphene_core::context_modification::ContextModificationNode<_, _>, input: Context, fn_params: [Context => Option<WgpuSurface>, Context => graphene_std::ContextFeatures]),
async_node!(graphene_core::context_modification::ContextModificationNode<_, _>, input: Context, fn_params: [Context => WindowHandle, Context => graphene_std::ContextFeatures]),
#[cfg(feature = "gpu")]
async_node!(graphene_core::context_modification::ContextModificationNode<_, _>, input: Context, fn_params: [Context => &WgpuExecutor, Context => graphene_std::ContextFeatures]),
// ==========
// MEMO NODES
// ==========
Expand Down Expand Up @@ -183,6 +185,8 @@ fn node_registry() -> HashMap<ProtoNodeIdentifier, HashMap<NodeIOTypes, NodeCons
#[cfg(feature = "gpu")]
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => WgpuSurface]),
#[cfg(feature = "gpu")]
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => &WgpuExecutor]),
#[cfg(feature = "gpu")]
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => Table<Raster<GPU>>]),
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => Option<f64>]),
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => Color]),
Expand Down
2 changes: 1 addition & 1 deletion node-graph/wgpu-executor/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ impl WgpuExecutor {
mip_level_count: 1,
sample_count: 1,
dimension: wgpu::TextureDimension::D2,
usage: wgpu::TextureUsages::STORAGE_BINDING | wgpu::TextureUsages::TEXTURE_BINDING,
usage: wgpu::TextureUsages::STORAGE_BINDING | wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_SRC,
format: VELLO_SURFACE_FORMAT,
view_formats: &[],
});
Expand Down