Skip to content

Commit 8c45949

Browse files
committed
Add implementation of rasterize node using vello
1 parent 84e4481 commit 8c45949

File tree

4 files changed

+79
-7
lines changed

4 files changed

+79
-7
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: 70 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,22 +3,19 @@ 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;
87
#[cfg(target_family = "wasm")]
98
use graphene_core::math::bbox::Bbox;
109
use graphene_core::raster::image::Image;
1110
use graphene_core::raster_types::{CPU, Raster};
1211
use graphene_core::table::Table;
13-
#[cfg(target_family = "wasm")]
1412
use graphene_core::transform::Footprint;
15-
#[cfg(target_family = "wasm")]
1613
use graphene_core::vector::Vector;
1714
use graphene_core::{Color, Ctx};
18-
#[cfg(target_family = "wasm")]
1915
use graphene_core::{Graphic, WasmNotSend};
16+
use graphene_svg_renderer::Render;
2017
#[cfg(target_family = "wasm")]
21-
use graphene_svg_renderer::{Render, RenderParams, RenderSvgSegmentList, SvgRender};
18+
use graphene_svg_renderer::{RenderParams, RenderSvgSegmentList, SvgRender};
2219
use std::sync::Arc;
2320
#[cfg(target_family = "wasm")]
2421
use wasm_bindgen::JsCast;
@@ -209,3 +206,71 @@ where
209206
..Default::default()
210207
})
211208
}
209+
210+
#[cfg(not(target_family = "wasm"))]
211+
#[node_macro::node(category(""))]
212+
async fn rasterize<'a: 'n, T: WasmNotSend + 'n>(
213+
_: impl Ctx,
214+
#[implementations(
215+
Table<Vector>,
216+
Table<Raster<CPU>>,
217+
Table<Graphic>,
218+
Table<Color>,
219+
Table<GradientStops>,
220+
)]
221+
mut data: Table<T>,
222+
footprint: Footprint,
223+
wgpu_executor: &'a wgpu_executor::WgpuExecutor,
224+
) -> Table<Raster<CPU>>
225+
where
226+
Table<T>: graphene_svg_renderer::Render,
227+
{
228+
use graphene_core::math::bbox::Bbox;
229+
use graphene_core::table::TableRow;
230+
use wgpu_executor::RenderContext;
231+
232+
if footprint.transform.matrix2.determinant() == 0. {
233+
log::trace!("Invalid footprint received for rasterization");
234+
return Table::new();
235+
}
236+
237+
let aabb = Bbox::from_transform(footprint.transform).to_axis_aligned_bbox();
238+
let resolution = footprint.resolution;
239+
240+
// Adjust data transforms to account for bounding box offset
241+
for row in data.iter_mut() {
242+
*row.transform = glam::DAffine2::from_translation(-aabb.start) * *row.transform;
243+
}
244+
245+
// Create Vello scene and render context
246+
let mut scene = vello::Scene::new();
247+
let mut context = RenderContext::default();
248+
249+
// Render data to Vello scene
250+
let render_params = graphene_svg_renderer::RenderParams {
251+
footprint: Footprint::default(),
252+
for_export: true,
253+
..Default::default()
254+
};
255+
data.render_to_vello(&mut scene, Default::default(), &mut context, &render_params);
256+
257+
// Render scene to texture
258+
let background = graphene_core::Color::TRANSPARENT;
259+
let wgpu_texture = wgpu_executor
260+
.render_vello_scene_to_texture(&scene, resolution, &context, background)
261+
.await
262+
.expect("Failed to render Vello scene to texture");
263+
264+
// Wrap the texture in a Raster<GPU>
265+
let gpu_raster = Raster::new_gpu(wgpu_texture);
266+
267+
// Convert GPU raster to CPU raster using Convert trait
268+
use graphene_core::ops::Convert;
269+
let cpu_raster = gpu_raster.convert(Footprint::default(), wgpu_executor).await;
270+
271+
Table::new_from_row(TableRow {
272+
element: cpu_raster,
273+
transform: footprint.transform,
274+
..Default::default()
275+
})
276+
}

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)