Skip to content

Commit 4351bac

Browse files
Implement Convert trait to convert between CPU and GPU images (#3194)
* Add upload texture trait * Make convert trait use explicit converter * Add gpu texture download implementation * Add footprint to convert trait * Cleanup texture upload / download * Download wgpu textures aligned * abstract texture download into converter helper * rename module not only doing uploads anymore conversion looks like a ok name * Remove into_iter call and intermediate vector allocation --------- Co-authored-by: Timon Schelling <[email protected]>
1 parent 3ec3135 commit 4351bac

File tree

9 files changed

+309
-72
lines changed

9 files changed

+309
-72
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -980,7 +980,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
980980
DocumentNode {
981981
inputs: vec![NodeInput::import(concrete!(Table<Raster<CPU>>), 0), NodeInput::node(NodeId(0), 0)],
982982
call_argument: generic!(T),
983-
implementation: DocumentNodeImplementation::ProtoNode(wgpu_executor::texture_upload::upload_texture::IDENTIFIER),
983+
implementation: DocumentNodeImplementation::ProtoNode(wgpu_executor::texture_conversion::upload_texture::IDENTIFIER),
984984
..Default::default()
985985
},
986986
DocumentNode {

node-graph/gcore/src/ops.rs

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
use crate::Node;
21
use graphene_core_shaders::Ctx;
2+
3+
use crate::{ExtractFootprint, Node, transform::Footprint};
34
use std::marker::PhantomData;
45

56
// TODO: Rename to "Passthrough"
@@ -49,25 +50,25 @@ fn into<'i, T: 'i + Send + Into<O>, O: 'i + Send>(_: impl Ctx, value: T, _out_ty
4950

5051
/// The [`Convert`] trait allows for conversion between Rust primitive numeric types.
5152
/// Because number casting is lossy, we cannot use the normal [`Into`] trait like we do for other types.
52-
pub trait Convert<T>: Sized {
53+
pub trait Convert<T, C>: Sized {
5354
/// Converts this type into the (usually inferred) output type.
5455
#[must_use]
55-
fn convert(self) -> T;
56+
fn convert(self, footprint: Footprint, converter: C) -> impl Future<Output = T> + Send;
5657
}
5758

58-
impl<T: ToString> Convert<String> for T {
59+
impl<T: ToString + Send> Convert<String, ()> for T {
5960
/// Converts this type into a `String` using its `ToString` implementation.
6061
#[inline]
61-
fn convert(self) -> String {
62+
async fn convert(self, _: Footprint, _converter: ()) -> String {
6263
self.to_string()
6364
}
6465
}
6566

6667
/// Implements the [`Convert`] trait for conversion between the cartesian product of Rust's primitive numeric types.
6768
macro_rules! impl_convert {
6869
($from:ty, $to:ty) => {
69-
impl Convert<$to> for $from {
70-
fn convert(self) -> $to {
70+
impl Convert<$to, ()> for $from {
71+
async fn convert(self, _: Footprint, _: ()) -> $to {
7172
self as $to
7273
}
7374
}
@@ -105,8 +106,8 @@ impl_convert!(isize);
105106
impl_convert!(usize);
106107

107108
#[node_macro::node(skip_impl)]
108-
fn convert<'i, T: 'i + Send + Convert<O>, O: 'i + Send>(_: impl Ctx, value: T, _out_ty: PhantomData<O>) -> O {
109-
value.convert()
109+
async fn convert<'i, T: 'i + Send + Convert<O, C>, O: 'i + Send, C: 'i + Send>(ctx: impl Ctx + ExtractFootprint, value: T, converter: C, _out_ty: PhantomData<O>) -> O {
110+
value.convert(*ctx.try_footprint().unwrap_or(&Footprint::DEFAULT), converter).await
110111
}
111112

112113
#[cfg(test)]

node-graph/gcore/src/registry.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use std::sync::{LazyLock, Mutex};
99
pub use graphene_core_shaders::registry::types;
1010

1111
// Translation struct between macro and definition
12-
#[derive(Clone)]
12+
#[derive(Clone, Debug)]
1313
pub struct NodeMetadata {
1414
pub display_name: &'static str,
1515
pub category: Option<&'static str>,

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

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,14 @@ fn node_registry() -> HashMap<ProtoNodeIdentifier, HashMap<NodeIOTypes, NodeCons
6161
convert_node!(from: DVec2, to: String),
6262
convert_node!(from: IVec2, to: String),
6363
convert_node!(from: DAffine2, to: String),
64+
#[cfg(feature = "gpu")]
65+
convert_node!(from: Table<Raster<CPU>>, to: Table<Raster<CPU>>, converter: &WgpuExecutor),
66+
#[cfg(feature = "gpu")]
67+
convert_node!(from: Table<Raster<CPU>>, to: Table<Raster<GPU>>, converter: &WgpuExecutor),
68+
#[cfg(feature = "gpu")]
69+
convert_node!(from: Table<Raster<GPU>>, to: Table<Raster<GPU>>, converter: &WgpuExecutor),
70+
#[cfg(feature = "gpu")]
71+
convert_node!(from: Table<Raster<GPU>>, to: Table<Raster<CPU>>, converter: &WgpuExecutor),
6472
// =============
6573
// MONITOR NODES
6674
// =============
@@ -394,21 +402,30 @@ mod node_registry_macros {
394402
x
395403
}};
396404
(from: $from:ty, to: $to:ty) => {
405+
convert_node!(from: $from, to: $to, converter: ())
406+
};
407+
(from: $from:ty, to: $to:ty, converter: $convert:ty) => {
397408
(
398409
ProtoNodeIdentifier::new(concat!["graphene_core::ops::ConvertNode<", stringify!($to), ">"]),
399410
|mut args| {
400411
Box::pin(async move {
401-
let node = graphene_core::ops::ConvertNode::new(graphene_std::any::downcast_node::<Context, $from>(args.pop().unwrap()),
402-
graphene_std::any::FutureWrapperNode::new(graphene_std::value::ClonedNode::new(std::marker::PhantomData::<$to>)) );
412+
let mut args = args.drain(..);
413+
let node = graphene_core::ops::ConvertNode::new(
414+
graphene_std::any::downcast_node::<Context, $from>(args.next().expect("Convert node did not get first argument")),
415+
graphene_std::any::downcast_node::<Context, $convert>(args.next().expect("Convert node did not get converter argument")),
416+
graphene_std::any::FutureWrapperNode::new(graphene_std::value::ClonedNode::new(std::marker::PhantomData::<$to>))
417+
);
403418
let any: DynAnyNode<Context, $to, _> = graphene_std::any::DynAnyNode::new(node);
404419
Box::new(any) as TypeErasedBox
405420
})
406421
},
407422
{
408-
let node = graphene_core::ops::ConvertNode::new(graphene_std::any::PanicNode::<Context, core::pin::Pin<Box<dyn core::future::Future<Output = $from> + Send>>>::new(),
409-
410-
graphene_std::any::FutureWrapperNode::new(graphene_std::value::ClonedNode::new(std::marker::PhantomData::<$to>)) );
411-
let params = vec![fn_type_fut!(Context, $from)];
423+
let node = graphene_core::ops::ConvertNode::new(
424+
graphene_std::any::PanicNode::<Context, core::pin::Pin<Box<dyn core::future::Future<Output = $from> + Send>>>::new(),
425+
graphene_std::any::PanicNode::<Context, core::pin::Pin<Box<dyn core::future::Future<Output = $convert> + Send>>>::new(),
426+
graphene_std::any::FutureWrapperNode::new(graphene_std::value::ClonedNode::new(std::marker::PhantomData::<$to>))
427+
);
428+
let params = vec![fn_type_fut!(Context, $from), fn_type_fut!(Context, $convert)];
412429
let node_io = NodeIO::<'_, Context>::to_async_node_io(&node, params);
413430
node_io
414431
},

node-graph/node-macro/src/shader_nodes/per_pixel_adjust.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ impl PerPixelAdjustCodegen<'_> {
128128
#(pub #uniform_members),*
129129
}
130130
};
131-
let uniform_struct_shader_struct_derive = crate::buffer_struct::derive_buffer_struct_struct(&self.crate_ident, &uniform_struct)?;
131+
let uniform_struct_shader_struct_derive = crate::buffer_struct::derive_buffer_struct_struct(self.crate_ident, &uniform_struct)?;
132132

133133
let image_params = self
134134
.params

node-graph/preprocessor/src/lib.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ pub fn generate_node_substitutions() -> HashMap<ProtoNodeIdentifier, DocumentNod
6767
1 => {
6868
let input = inputs.iter().next().unwrap();
6969
let input_ty = input.nested_type();
70+
let mut inputs = vec![NodeInput::import(input.clone(), i)];
7071

7172
let into_node_identifier = ProtoNodeIdentifier {
7273
name: format!("graphene_core::ops::IntoNode<{}>", input_ty.clone()).into(),
@@ -80,13 +81,14 @@ pub fn generate_node_substitutions() -> HashMap<ProtoNodeIdentifier, DocumentNod
8081
into_node_identifier
8182
} else if into_node_registry.keys().any(|ident| ident.name.as_ref() == convert_node_identifier.name.as_ref()) {
8283
generated_nodes += 1;
84+
inputs.push(NodeInput::value(TaggedValue::None, false));
8385
convert_node_identifier
8486
} else {
8587
identity_node.clone()
8688
};
8789

8890
DocumentNode {
89-
inputs: vec![NodeInput::import(input.clone(), i)],
91+
inputs,
9092
implementation: DocumentNodeImplementation::ProtoNode(proto_node),
9193
visible: true,
9294
..Default::default()

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
mod context;
22
pub mod shader_runtime;
3-
pub mod texture_upload;
3+
pub mod texture_conversion;
44

55
use crate::shader_runtime::ShaderRuntime;
66
use anyhow::Result;

0 commit comments

Comments
 (0)