mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-29 09:58:11 +08:00
Prototype vector to raster conversion
This commit is contained in:
Generated
+3
@@ -4549,6 +4549,7 @@ dependencies = [
|
|||||||
"graphene-std",
|
"graphene-std",
|
||||||
"interpreted-executor",
|
"interpreted-executor",
|
||||||
"log",
|
"log",
|
||||||
|
"wgpu-executor",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -7159,6 +7160,8 @@ dependencies = [
|
|||||||
"futures",
|
"futures",
|
||||||
"glam",
|
"glam",
|
||||||
"graphene-application-io",
|
"graphene-application-io",
|
||||||
|
"graphic-types",
|
||||||
|
"log",
|
||||||
"node-macro",
|
"node-macro",
|
||||||
"raster-types",
|
"raster-types",
|
||||||
"rendering",
|
"rendering",
|
||||||
|
|||||||
@@ -344,7 +344,7 @@ impl ProtoNetwork {
|
|||||||
let (_, node) = &self.nodes[old_node_id.0 as usize];
|
let (_, node) = &self.nodes[old_node_id.0 as usize];
|
||||||
let mut path = node.original_location.path.clone();
|
let mut path = node.original_location.path.clone();
|
||||||
|
|
||||||
log::debug!("Inserting context nullification after {:?} with context features: {:?}", node.identifier, context_deps);
|
// log::debug!("Inserting context nullification after {:?} with context features: {:?}", node.identifier, context_deps);
|
||||||
|
|
||||||
// Add a path extension with a placeholder value which should not conflict with existing paths
|
// Add a path extension with a placeholder value which should not conflict with existing paths
|
||||||
if let Some(p) = path.as_mut() {
|
if let Some(p) = path.as_mut() {
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ use graph_craft::document::DocumentNode;
|
|||||||
use graph_craft::document::value::RenderOutput;
|
use graph_craft::document::value::RenderOutput;
|
||||||
use graph_craft::proto::{NodeConstructor, TypeErasedBox};
|
use graph_craft::proto::{NodeConstructor, TypeErasedBox};
|
||||||
use graphene_std::Artboard;
|
use graphene_std::Artboard;
|
||||||
use graphene_std::Context;
|
|
||||||
use graphene_std::Graphic;
|
use graphene_std::Graphic;
|
||||||
use graphene_std::any::DynAnyNode;
|
use graphene_std::any::DynAnyNode;
|
||||||
use graphene_std::application_io::{ImageTexture, SurfaceFrame};
|
use graphene_std::application_io::{ImageTexture, SurfaceFrame};
|
||||||
@@ -25,6 +24,7 @@ use graphene_std::vector::Vector;
|
|||||||
use graphene_std::wasm_application_io::WasmEditorApi;
|
use graphene_std::wasm_application_io::WasmEditorApi;
|
||||||
#[cfg(feature = "gpu")]
|
#[cfg(feature = "gpu")]
|
||||||
use graphene_std::wasm_application_io::WasmSurfaceHandle;
|
use graphene_std::wasm_application_io::WasmSurfaceHandle;
|
||||||
|
use graphene_std::{Context, ContextFeatures};
|
||||||
use graphene_std::{Cow, ProtoNodeIdentifier};
|
use graphene_std::{Cow, ProtoNodeIdentifier};
|
||||||
use graphene_std::{NodeIO, NodeIOTypes};
|
use graphene_std::{NodeIO, NodeIOTypes};
|
||||||
use graphene_std::{fn_type_fut, future};
|
use graphene_std::{fn_type_fut, future};
|
||||||
@@ -45,9 +45,9 @@ fn node_registry() -> HashMap<ProtoNodeIdentifier, HashMap<NodeIOTypes, NodeCons
|
|||||||
// ==========
|
// ==========
|
||||||
into_node!(from: Table<Graphic>, to: Table<Graphic>),
|
into_node!(from: Table<Graphic>, to: Table<Graphic>),
|
||||||
into_node!(from: Table<Vector>, to: Table<Vector>),
|
into_node!(from: Table<Vector>, to: Table<Vector>),
|
||||||
into_node!(from: Table<Raster<CPU>>, to: Table<Raster<CPU>>),
|
// into_node!(from: Table<Raster<CPU>>, to: Table<Raster<CPU>>),
|
||||||
#[cfg(feature = "gpu")]
|
// #[cfg(feature = "gpu")]
|
||||||
into_node!(from: Table<Raster<GPU>>, to: Table<Raster<GPU>>),
|
// into_node!(from: Table<Raster<GPU>>, to: Table<Raster<GPU>>),
|
||||||
convert_node!(from: Table<Vector>, to: Table<Graphic>),
|
convert_node!(from: Table<Vector>, to: Table<Graphic>),
|
||||||
convert_node!(from: Table<Raster<CPU>>, to: Table<Graphic>),
|
convert_node!(from: Table<Raster<CPU>>, to: Table<Graphic>),
|
||||||
#[cfg(feature = "gpu")]
|
#[cfg(feature = "gpu")]
|
||||||
@@ -69,6 +69,8 @@ fn node_registry() -> HashMap<ProtoNodeIdentifier, HashMap<NodeIOTypes, NodeCons
|
|||||||
convert_node!(from: Table<Raster<GPU>>, to: Table<Raster<GPU>>, converter: &WgpuExecutor),
|
convert_node!(from: Table<Raster<GPU>>, to: Table<Raster<GPU>>, converter: &WgpuExecutor),
|
||||||
#[cfg(feature = "gpu")]
|
#[cfg(feature = "gpu")]
|
||||||
convert_node!(from: Table<Raster<GPU>>, to: Table<Raster<CPU>>, converter: &WgpuExecutor),
|
convert_node!(from: Table<Raster<GPU>>, to: Table<Raster<CPU>>, converter: &WgpuExecutor),
|
||||||
|
#[cfg(feature = "gpu")]
|
||||||
|
convert_node!(from: Table<Vector>, to: Table<Raster<GPU>>, converter: &WgpuExecutor),
|
||||||
// =============
|
// =============
|
||||||
// MONITOR NODES
|
// MONITOR NODES
|
||||||
// =============
|
// =============
|
||||||
@@ -186,6 +188,8 @@ fn node_registry() -> HashMap<ProtoNodeIdentifier, HashMap<NodeIOTypes, NodeCons
|
|||||||
#[cfg(feature = "gpu")]
|
#[cfg(feature = "gpu")]
|
||||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => WgpuSurface]),
|
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => WgpuSurface]),
|
||||||
#[cfg(feature = "gpu")]
|
#[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 => 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 => Option<f64>]),
|
||||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => Color]),
|
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => Color]),
|
||||||
@@ -396,7 +400,6 @@ mod node_registry_macros {
|
|||||||
(
|
(
|
||||||
ProtoNodeIdentifier::new(concat!["graphene_core::ops::ConvertNode<", stringify!($to), ">"]),
|
ProtoNodeIdentifier::new(concat!["graphene_core::ops::ConvertNode<", stringify!($to), ">"]),
|
||||||
|mut args| {
|
|mut args| {
|
||||||
log::debug!("registering convert from {:?} to {:?} with {:?}", stringify!($from), stringify!($to), stringify!($convert));
|
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
let mut args = args.drain(..);
|
let mut args = args.drain(..);
|
||||||
let node = graphene_std::ops::ConvertNode::new(
|
let node = graphene_std::ops::ConvertNode::new(
|
||||||
@@ -417,7 +420,6 @@ mod node_registry_macros {
|
|||||||
);
|
);
|
||||||
let params = vec![fn_type_fut!(Context, $from), fn_type_fut!(Context, $convert)];
|
let params = vec![fn_type_fut!(Context, $from), fn_type_fut!(Context, $convert)];
|
||||||
let node_io = NodeIO::<'_, Context>::to_async_node_io(&node, params);
|
let node_io = NodeIO::<'_, Context>::to_async_node_io(&node, params);
|
||||||
// log::debug!("node io: {:?}", node_io);
|
|
||||||
node_io
|
node_io
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ license = "MIT OR Apache-2.0"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
# Local dependencies
|
# Local dependencies
|
||||||
core-types = { workspace = true }
|
core-types = { workspace = true }
|
||||||
|
graphic-types = { workspace = true }
|
||||||
raster-types = { workspace = true, features = ["wgpu"] }
|
raster-types = { workspace = true, features = ["wgpu"] }
|
||||||
graphene-application-io = { workspace = true, features = ["wgpu"] }
|
graphene-application-io = { workspace = true, features = ["wgpu"] }
|
||||||
rendering = { workspace = true }
|
rendering = { workspace = true }
|
||||||
@@ -22,3 +23,4 @@ web-sys = { workspace = true }
|
|||||||
winit = { workspace = true }
|
winit = { workspace = true }
|
||||||
vello = { workspace = true }
|
vello = { workspace = true }
|
||||||
bytemuck = { workspace = true }
|
bytemuck = { workspace = true }
|
||||||
|
log = { workspace = true }
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
mod context;
|
mod context;
|
||||||
pub mod shader_runtime;
|
pub mod shader_runtime;
|
||||||
pub mod texture_conversion;
|
pub mod texture_conversion;
|
||||||
|
pub mod vector_to_raster;
|
||||||
|
|
||||||
use crate::shader_runtime::ShaderRuntime;
|
use crate::shader_runtime::ShaderRuntime;
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
|
|||||||
@@ -0,0 +1,75 @@
|
|||||||
|
use crate::WgpuExecutor;
|
||||||
|
use core_types::ops::Convert;
|
||||||
|
use core_types::table::Table;
|
||||||
|
use core_types::transform::Footprint;
|
||||||
|
use graphic_types::Vector;
|
||||||
|
use graphic_types::raster_types::{GPU, Raster};
|
||||||
|
use rendering::{Render, RenderOutputType, RenderParams};
|
||||||
|
use wgpu::{CommandEncoderDescriptor, TextureFormat, TextureViewDescriptor};
|
||||||
|
|
||||||
|
/// Converts Table<Vector> to Table<Raster<GPU>> by rendering each vector to Vello scene and then to texture
|
||||||
|
impl<'i> Convert<Table<Raster<GPU>>, &'i WgpuExecutor> for Table<Vector> {
|
||||||
|
async fn convert(self, footprint: Footprint, executor: &'i WgpuExecutor) -> Table<Raster<GPU>> {
|
||||||
|
// Create render parameters for Vello rendering
|
||||||
|
let render_params = RenderParams {
|
||||||
|
render_mode: graphic_types::vector_types::vector::style::RenderMode::Normal,
|
||||||
|
hide_artboards: false,
|
||||||
|
for_export: false,
|
||||||
|
render_output_type: RenderOutputType::Vello,
|
||||||
|
footprint,
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
log::debug!("rasterizing vector data with footprint {footprint:?}");
|
||||||
|
|
||||||
|
let vector = &self;
|
||||||
|
log::debug!("{:?}", vector);
|
||||||
|
|
||||||
|
// Create a Vello scene for this vector
|
||||||
|
let mut scene = vello::Scene::new();
|
||||||
|
let mut context = crate::RenderContext::default();
|
||||||
|
|
||||||
|
// Render the vector to the Vello scene with the row's transform
|
||||||
|
vector.render_to_vello(&mut scene, footprint.transform, &mut context, &render_params);
|
||||||
|
|
||||||
|
// Render the scene to a GPU texture
|
||||||
|
let resolution = footprint.resolution;
|
||||||
|
let background = core_types::Color::BLACK;
|
||||||
|
|
||||||
|
// Use async rendering to get the texture
|
||||||
|
let texture = async {
|
||||||
|
executor
|
||||||
|
.render_vello_scene_to_texture(&scene, resolution, &context, background)
|
||||||
|
.await
|
||||||
|
.expect("Failed to render Vello scene to texture")
|
||||||
|
};
|
||||||
|
|
||||||
|
// Block on the texture creation (we're in an async context)
|
||||||
|
let texture = futures::executor::block_on(texture);
|
||||||
|
let device = &executor.context.device;
|
||||||
|
let queue = &executor.context.queue;
|
||||||
|
let mut encoder = device.create_command_encoder(&CommandEncoderDescriptor::default());
|
||||||
|
let blitter = wgpu::util::TextureBlitter::new(device, TextureFormat::Rgba8UnormSrgb);
|
||||||
|
let view = texture.create_view(&TextureViewDescriptor::default());
|
||||||
|
let new_texture = device.create_texture(&wgpu::wgt::TextureDescriptor {
|
||||||
|
label: None,
|
||||||
|
size: wgpu::Extent3d {
|
||||||
|
width: texture.width(),
|
||||||
|
height: texture.height(),
|
||||||
|
depth_or_array_layers: 1,
|
||||||
|
},
|
||||||
|
mip_level_count: 1,
|
||||||
|
sample_count: 1,
|
||||||
|
dimension: wgpu::TextureDimension::D2,
|
||||||
|
usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::RENDER_ATTACHMENT,
|
||||||
|
format: TextureFormat::Rgba8UnormSrgb,
|
||||||
|
view_formats: &[],
|
||||||
|
});
|
||||||
|
let new_view = new_texture.create_view(&TextureViewDescriptor::default());
|
||||||
|
|
||||||
|
blitter.copy(device, &mut encoder, &view, &new_view);
|
||||||
|
let command_buffer = encoder.finish();
|
||||||
|
queue.submit([command_buffer]);
|
||||||
|
|
||||||
|
Table::new_from_element(Raster::new_gpu(new_texture))
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -9,6 +9,7 @@ use graphene_application_io::{ApplicationIo, ExportFormat, ImageTexture, RenderC
|
|||||||
use graphic_types::Artboard;
|
use graphic_types::Artboard;
|
||||||
use graphic_types::Graphic;
|
use graphic_types::Graphic;
|
||||||
use graphic_types::Vector;
|
use graphic_types::Vector;
|
||||||
|
use graphic_types::raster_types::GPU;
|
||||||
use graphic_types::raster_types::Image;
|
use graphic_types::raster_types::Image;
|
||||||
use graphic_types::raster_types::{CPU, Raster};
|
use graphic_types::raster_types::{CPU, Raster};
|
||||||
use rendering::{Render, RenderOutputType as RenderOutputTypeRequest, RenderParams, RenderSvgSegmentList, SvgRender, format_transform_matrix};
|
use rendering::{Render, RenderOutputType as RenderOutputTypeRequest, RenderParams, RenderSvgSegmentList, SvgRender, format_transform_matrix};
|
||||||
@@ -40,6 +41,7 @@ async fn render_intermediate<'a: 'n, T: 'static + Render + WasmNotSend + Send +
|
|||||||
Context -> Table<Graphic>,
|
Context -> Table<Graphic>,
|
||||||
Context -> Table<Vector>,
|
Context -> Table<Vector>,
|
||||||
Context -> Table<Raster<CPU>>,
|
Context -> Table<Raster<CPU>>,
|
||||||
|
Context -> Table<Raster<GPU>>,
|
||||||
Context -> Table<Color>,
|
Context -> Table<Color>,
|
||||||
Context -> Table<GradientStops>,
|
Context -> Table<GradientStops>,
|
||||||
)]
|
)]
|
||||||
|
|||||||
@@ -11,5 +11,6 @@ log = { workspace = true }
|
|||||||
|
|
||||||
# Workspace dependencies
|
# Workspace dependencies
|
||||||
graphene-std = { workspace = true, features = ["gpu"] }
|
graphene-std = { workspace = true, features = ["gpu"] }
|
||||||
|
wgpu-executor = { workspace = true }
|
||||||
graph-craft = { workspace = true }
|
graph-craft = { workspace = true }
|
||||||
interpreted-executor = { workspace = true }
|
interpreted-executor = { workspace = true }
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ use graph_craft::{ProtoNodeIdentifier, concrete};
|
|||||||
use graphene_std::registry::*;
|
use graphene_std::registry::*;
|
||||||
use graphene_std::*;
|
use graphene_std::*;
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
|
use wgpu_executor::WgpuExecutor;
|
||||||
|
|
||||||
pub fn expand_network(network: &mut NodeNetwork, substitutions: &HashMap<ProtoNodeIdentifier, DocumentNode>) {
|
pub fn expand_network(network: &mut NodeNetwork, substitutions: &HashMap<ProtoNodeIdentifier, DocumentNode>) {
|
||||||
if network.generated {
|
if network.generated {
|
||||||
@@ -76,12 +77,20 @@ pub fn generate_node_substitutions() -> HashMap<ProtoNodeIdentifier, DocumentNod
|
|||||||
name: format!("graphene_core::ops::ConvertNode<{}>", input_ty.clone()).into(),
|
name: format!("graphene_core::ops::ConvertNode<{}>", input_ty.clone()).into(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let mut context_features = ContextDependencies::default();
|
||||||
let proto_node = if into_node_registry.keys().any(|ident: &ProtoNodeIdentifier| ident.name.as_ref() == into_node_identifier.name.as_ref()) {
|
let proto_node = if into_node_registry.keys().any(|ident: &ProtoNodeIdentifier| ident.name.as_ref() == into_node_identifier.name.as_ref()) {
|
||||||
generated_nodes += 1;
|
generated_nodes += 1;
|
||||||
into_node_identifier
|
into_node_identifier
|
||||||
} else if into_node_registry.keys().any(|ident| ident.name.as_ref() == convert_node_identifier.name.as_ref()) {
|
} else if let Some(impls) = into_node_registry.get(&convert_node_identifier) {
|
||||||
generated_nodes += 1;
|
generated_nodes += 1;
|
||||||
inputs.push(NodeInput::value(TaggedValue::None, false));
|
let converter = match impls.keys().next() {
|
||||||
|
Some(node_io) if node_io.inputs[1].nested_type() == &concrete!(&WgpuExecutor) => {
|
||||||
|
context_features.extract |= ContextFeatures::FOOTPRINT;
|
||||||
|
NodeInput::scope("wgpu-executor")
|
||||||
|
}
|
||||||
|
_ => NodeInput::value(TaggedValue::None, false),
|
||||||
|
};
|
||||||
|
inputs.push(converter);
|
||||||
convert_node_identifier
|
convert_node_identifier
|
||||||
} else {
|
} else {
|
||||||
identity_node.clone()
|
identity_node.clone()
|
||||||
@@ -93,6 +102,7 @@ pub fn generate_node_substitutions() -> HashMap<ProtoNodeIdentifier, DocumentNod
|
|||||||
implementation: DocumentNodeImplementation::ProtoNode(proto_node),
|
implementation: DocumentNodeImplementation::ProtoNode(proto_node),
|
||||||
visible: true,
|
visible: true,
|
||||||
original_location,
|
original_location,
|
||||||
|
context_features,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user