Skip to content

Commit 5b7e4a7

Browse files
committed
Add implementation of rasterize node using vello
1 parent ffc7427 commit 5b7e4a7

File tree

4 files changed

+78
-8
lines changed

4 files changed

+78
-8
lines changed

editor/src/messages/portfolio/document/node_graph/document_node_definitions.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -481,7 +481,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
481481
description: Cow::Borrowed("Loads an image from a given URL"),
482482
properties: None,
483483
},
484-
#[cfg(all(feature = "gpu", target_family = "wasm"))]
484+
#[cfg(feature = "gpu")]
485485
DocumentNodeDefinition {
486486
identifier: "Rasterize",
487487
category: "Raster",
@@ -502,7 +502,10 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
502502
..Default::default()
503503
},
504504
DocumentNode {
505+
#[cfg(target_family = "wasm")]
505506
inputs: vec![NodeInput::import(generic!(T), 0), NodeInput::import(concrete!(Footprint), 1), NodeInput::node(NodeId(1), 0)],
507+
#[cfg(not(target_family = "wasm"))]
508+
inputs: vec![NodeInput::import(generic!(T), 0), NodeInput::import(concrete!(Footprint), 1), NodeInput::scope("wgpu-executor")],
506509
implementation: DocumentNodeImplementation::ProtoNode(wasm_application_io::rasterize::IDENTIFIER),
507510
..Default::default()
508511
},

node-graph/gstd/src/wasm_application_io.rs

Lines changed: 69 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,15 @@ use base64::Engine;
33
pub use graph_craft::document::value::RenderOutputType;
44
pub use graph_craft::wasm_application_io::*;
55
use graphene_application_io::ApplicationIo;
6-
#[cfg(target_family = "wasm")]
76
use graphene_core::gradient::GradientStops;
8-
#[cfg(target_family = "wasm")]
97
use graphene_core::math::bbox::Bbox;
108
use graphene_core::raster::image::Image;
119
use graphene_core::raster_types::{CPU, Raster};
1210
use graphene_core::table::Table;
13-
#[cfg(target_family = "wasm")]
1411
use graphene_core::transform::Footprint;
15-
#[cfg(target_family = "wasm")]
1612
use graphene_core::vector::Vector;
1713
use graphene_core::{Color, Ctx};
18-
#[cfg(target_family = "wasm")]
1914
use graphene_core::{Graphic, WasmNotSend};
20-
#[cfg(target_family = "wasm")]
2115
use graphene_svg_renderer::{Render, RenderParams, RenderSvgSegmentList, SvgRender};
2216
use std::sync::Arc;
2317
#[cfg(target_family = "wasm")]
@@ -209,3 +203,72 @@ where
209203
..Default::default()
210204
})
211205
}
206+
207+
#[cfg(not(target_family = "wasm"))]
208+
#[node_macro::node(category(""))]
209+
async fn rasterize<'a: 'n, T: WasmNotSend + 'n>(
210+
_: impl Ctx,
211+
#[implementations(
212+
Table<Vector>,
213+
Table<Raster<CPU>>,
214+
Table<Graphic>,
215+
Table<Color>,
216+
Table<GradientStops>,
217+
)]
218+
mut data: Table<T>,
219+
footprint: Footprint,
220+
wgpu_executor: &'a wgpu_executor::WgpuExecutor,
221+
) -> Table<Raster<CPU>>
222+
where
223+
Table<T>: graphene_svg_renderer::Render,
224+
{
225+
use graphene_core::math::bbox::Bbox;
226+
use graphene_core::table::TableRow;
227+
use wgpu_executor::RenderContext;
228+
229+
if footprint.transform.matrix2.determinant() == 0. {
230+
log::trace!("Invalid footprint received for rasterization");
231+
return Table::new();
232+
}
233+
234+
let aabb = Bbox::from_transform(footprint.transform).to_axis_aligned_bbox();
235+
let resolution = footprint.resolution;
236+
237+
// Adjust data transforms to account for bounding box offset
238+
for row in data.iter_mut() {
239+
*row.transform = glam::DAffine2::from_translation(-aabb.start) * *row.transform;
240+
}
241+
242+
// Create Vello scene and render context
243+
let mut scene = vello::Scene::new();
244+
let mut context = RenderContext::default();
245+
246+
// Render data to Vello scene
247+
let render_params = graphene_svg_renderer::RenderParams {
248+
footprint: Footprint::default(),
249+
for_export: true,
250+
..Default::default()
251+
};
252+
data.render_to_vello(&mut scene, Default::default(), &mut context, &render_params);
253+
254+
// Render scene to texture
255+
let background = graphene_core::Color::TRANSPARENT;
256+
let wgpu_texture = wgpu_executor
257+
.render_vello_scene_to_texture(&scene, resolution, &context, background)
258+
.await
259+
.expect("Failed to render Vello scene to texture");
260+
261+
// Wrap the texture in a Raster<GPU>
262+
use graphene_core::raster_types::GPU;
263+
let gpu_raster = Raster::new_gpu(wgpu_texture);
264+
265+
// Convert GPU raster to CPU raster using Convert trait
266+
use graphene_core::ops::Convert;
267+
let cpu_raster = gpu_raster.convert(Footprint::default(), wgpu_executor).await;
268+
269+
Table::new_from_row(TableRow {
270+
element: cpu_raster,
271+
transform: footprint.transform,
272+
..Default::default()
273+
})
274+
}

node-graph/interpreted-executor/src/node_registry.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,8 @@ fn node_registry() -> HashMap<ProtoNodeIdentifier, HashMap<NodeIOTypes, NodeCons
148148
async_node!(graphene_core::context_modification::ContextModificationNode<_, _>, input: Context, fn_params: [Context => WgpuSurface, Context => graphene_std::ContextFeatures]),
149149
async_node!(graphene_core::context_modification::ContextModificationNode<_, _>, input: Context, fn_params: [Context => Option<WgpuSurface>, Context => graphene_std::ContextFeatures]),
150150
async_node!(graphene_core::context_modification::ContextModificationNode<_, _>, input: Context, fn_params: [Context => WindowHandle, Context => graphene_std::ContextFeatures]),
151+
#[cfg(feature = "gpu")]
152+
async_node!(graphene_core::context_modification::ContextModificationNode<_, _>, input: Context, fn_params: [Context => &WgpuExecutor, Context => graphene_std::ContextFeatures]),
151153
// ==========
152154
// MEMO NODES
153155
// ==========
@@ -183,6 +185,8 @@ fn node_registry() -> HashMap<ProtoNodeIdentifier, HashMap<NodeIOTypes, NodeCons
183185
#[cfg(feature = "gpu")]
184186
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => WgpuSurface]),
185187
#[cfg(feature = "gpu")]
188+
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => &WgpuExecutor]),
189+
#[cfg(feature = "gpu")]
186190
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => Table<Raster<GPU>>]),
187191
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => Option<f64>]),
188192
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => Color]),

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ impl WgpuExecutor {
124124
mip_level_count: 1,
125125
sample_count: 1,
126126
dimension: wgpu::TextureDimension::D2,
127-
usage: wgpu::TextureUsages::STORAGE_BINDING | wgpu::TextureUsages::TEXTURE_BINDING,
127+
usage: wgpu::TextureUsages::STORAGE_BINDING | wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_SRC,
128128
format: VELLO_SURFACE_FORMAT,
129129
view_formats: &[],
130130
});

0 commit comments

Comments
 (0)