Add the first basic version of the GPU blend node (#1243)
* Implement Gpu Blend node * Remove duplicate shader input * Fix formatting --------- Co-authored-by: Dennis Kobert <dennis@kobert.dev>
This commit is contained in:
parent
9da83d3280
commit
57415b948b
|
|
@ -651,6 +651,7 @@ dependencies = [
|
||||||
"gpu-compiler-bin-wrapper",
|
"gpu-compiler-bin-wrapper",
|
||||||
"gpu-executor",
|
"gpu-executor",
|
||||||
"graph-craft",
|
"graph-craft",
|
||||||
|
"graphene-core",
|
||||||
"reqwest",
|
"reqwest",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"tempfile",
|
"tempfile",
|
||||||
|
|
|
||||||
|
|
@ -723,6 +723,20 @@ fn static_nodes() -> Vec<DocumentNodeType> {
|
||||||
outputs: vec![DocumentOutputType::new("Image", FrontendGraphDataType::Raster)],
|
outputs: vec![DocumentOutputType::new("Image", FrontendGraphDataType::Raster)],
|
||||||
properties: node_properties::no_properties,
|
properties: node_properties::no_properties,
|
||||||
},
|
},
|
||||||
|
#[cfg(feature = "gpu")]
|
||||||
|
DocumentNodeType {
|
||||||
|
name: "Blend (GPU)",
|
||||||
|
category: "Image Adjustments",
|
||||||
|
identifier: NodeImplementation::proto("graphene_std::executor::BlendGpuImageNode<_, _, _>"),
|
||||||
|
inputs: vec![
|
||||||
|
DocumentInputType::value("Image", TaggedValue::ImageFrame(ImageFrame::empty()), true),
|
||||||
|
DocumentInputType::value("Second", TaggedValue::ImageFrame(ImageFrame::empty()), true),
|
||||||
|
DocumentInputType::value("Blend Mode", TaggedValue::BlendMode(BlendMode::Normal), false),
|
||||||
|
DocumentInputType::value("Opacity", TaggedValue::F32(100.0), false),
|
||||||
|
],
|
||||||
|
outputs: vec![DocumentOutputType::new("Image", FrontendGraphDataType::Raster)],
|
||||||
|
properties: node_properties::blend_properties,
|
||||||
|
},
|
||||||
DocumentNodeType {
|
DocumentNodeType {
|
||||||
name: "Extract",
|
name: "Extract",
|
||||||
category: "Macros",
|
category: "Macros",
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ serde_json = "1.0"
|
||||||
graph-craft = { version = "0.1.0", path = "../graph-craft", features = [
|
graph-craft = { version = "0.1.0", path = "../graph-craft", features = [
|
||||||
"serde",
|
"serde",
|
||||||
] }
|
] }
|
||||||
|
graphene-core = { version = "0.1.0", path = "../gcore" }
|
||||||
gpu-executor = { version = "0.1.0", path = "../gpu-executor" }
|
gpu-executor = { version = "0.1.0", path = "../gpu-executor" }
|
||||||
gpu-compiler-bin-wrapper = { version = "0.1.0", path = "../gpu-compiler/gpu-compiler-bin-wrapper" }
|
gpu-compiler-bin-wrapper = { version = "0.1.0", path = "../gpu-compiler/gpu-compiler-bin-wrapper" }
|
||||||
tempfile = "3.3.0"
|
tempfile = "3.3.0"
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,11 @@
|
||||||
use gpu_compiler_bin_wrapper::CompileRequest;
|
use gpu_compiler_bin_wrapper::CompileRequest;
|
||||||
use gpu_executor::{ShaderIO, ShaderInput};
|
use gpu_executor::{ShaderIO, ShaderInput};
|
||||||
use graph_craft::concrete;
|
use graph_craft::concrete;
|
||||||
|
use graph_craft::document::value::TaggedValue;
|
||||||
use graph_craft::document::*;
|
use graph_craft::document::*;
|
||||||
use graph_craft::*;
|
use graph_craft::*;
|
||||||
|
use graphene_core::raster::adjustments::{BlendMode, BlendNode};
|
||||||
|
use graphene_core::Color;
|
||||||
|
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
@ -10,33 +13,21 @@ use std::time::Duration;
|
||||||
fn main() {
|
fn main() {
|
||||||
let client = reqwest::blocking::Client::new();
|
let client = reqwest::blocking::Client::new();
|
||||||
|
|
||||||
// let network = NodeNetwork {
|
|
||||||
// inputs: vec![0],
|
|
||||||
// outputs: vec![NodeOutput::new(0, 0)],
|
|
||||||
// disabled: vec![],
|
|
||||||
// previous_outputs: None,
|
|
||||||
// nodes: [(
|
|
||||||
// 0,
|
|
||||||
// DocumentNode {
|
|
||||||
// name: "Inc".into(),
|
|
||||||
// inputs: vec![NodeInput::Network(concrete!(u32))],
|
|
||||||
// implementation: DocumentNodeImplementation::Network(add_network()),
|
|
||||||
// metadata: DocumentNodeMetadata::default(),
|
|
||||||
// },
|
|
||||||
// )]
|
|
||||||
// .into_iter()
|
|
||||||
// .collect(),
|
|
||||||
// };
|
|
||||||
let network = add_network();
|
let network = add_network();
|
||||||
let compiler = graph_craft::executor::Compiler {};
|
let compiler = graph_craft::executor::Compiler {};
|
||||||
let proto_network = compiler.compile_single(network, true).unwrap();
|
let proto_network = compiler.compile_single(network, true).unwrap();
|
||||||
|
|
||||||
let io = ShaderIO {
|
let io = ShaderIO {
|
||||||
inputs: vec![ShaderInput::StorageBuffer((), concrete!(u32))],
|
inputs: vec![
|
||||||
output: ShaderInput::OutputBuffer((), concrete!(&mut [u32])),
|
ShaderInput::StorageBuffer((), concrete!(Color)), // background image
|
||||||
|
ShaderInput::StorageBuffer((), concrete!(Color)), // foreground image
|
||||||
|
ShaderInput::StorageBuffer((), concrete!(u32)), // width/height of the foreground image
|
||||||
|
ShaderInput::OutputBuffer((), concrete!(Color)),
|
||||||
|
],
|
||||||
|
output: ShaderInput::OutputBuffer((), concrete!(Color)),
|
||||||
};
|
};
|
||||||
|
|
||||||
let compile_request = CompileRequest::new(vec![proto_network], vec![concrete!(u32)], vec![concrete!(u32)], io);
|
let compile_request = CompileRequest::new(vec![proto_network], vec![concrete!(Color), concrete!(Color), concrete!(u32)], vec![concrete!(Color)], io);
|
||||||
let response = client
|
let response = client
|
||||||
.post("http://localhost:3000/compile/spirv")
|
.post("http://localhost:3000/compile/spirv")
|
||||||
.timeout(Duration::from_secs(30))
|
.timeout(Duration::from_secs(30))
|
||||||
|
|
@ -52,27 +43,33 @@ fn add_network() -> NodeNetwork {
|
||||||
outputs: vec![NodeOutput::new(0, 0)],
|
outputs: vec![NodeOutput::new(0, 0)],
|
||||||
disabled: vec![],
|
disabled: vec![],
|
||||||
previous_outputs: None,
|
previous_outputs: None,
|
||||||
nodes: [
|
nodes: [DocumentNode {
|
||||||
(
|
name: "Blend Image".into(),
|
||||||
0,
|
inputs: vec![NodeInput::Inline(InlineRust::new(
|
||||||
DocumentNode {
|
format!(
|
||||||
name: "Dup".into(),
|
r#"graphene_core::raster::adjustments::BlendNode::new(
|
||||||
inputs: vec![NodeInput::value(value::TaggedValue::U32(5u32), false)],
|
graphene_core::value::CopiedNode::new({}),
|
||||||
implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_core::ops::IdNode")),
|
graphene_core::value::CopiedNode::new({}),
|
||||||
..Default::default()
|
).eval((
|
||||||
},
|
i1[_global_index.x as usize],
|
||||||
|
if _global_index.x < i2[2] {{
|
||||||
|
i0[_global_index.x as usize]
|
||||||
|
}} else {{
|
||||||
|
Color::from_rgbaf32_unchecked(0.0, 0.0, 0.0, 0.0)
|
||||||
|
}},
|
||||||
|
))"#,
|
||||||
|
TaggedValue::BlendMode(BlendMode::Normal).to_primitive_string(),
|
||||||
|
TaggedValue::F32(1.0).to_primitive_string(),
|
||||||
),
|
),
|
||||||
// (
|
concrete![Color],
|
||||||
// 1,
|
))],
|
||||||
// DocumentNode {
|
implementation: DocumentNodeImplementation::Unresolved("graphene_core::value::CopiedNode".into()),
|
||||||
// name: "Add".into(),
|
..Default::default()
|
||||||
// inputs: vec![NodeInput::node(0, 0)],
|
}]
|
||||||
// metadata: DocumentNodeMetadata::default(),
|
|
||||||
// implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_core::ops::AddNode")),
|
|
||||||
// },
|
|
||||||
// ),
|
|
||||||
]
|
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
.enumerate()
|
||||||
|
.map(|(i, n)| (i as u64, n))
|
||||||
.collect(),
|
.collect(),
|
||||||
|
..Default::default()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -84,6 +84,7 @@ impl BlendMode {
|
||||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
#[cfg_attr(feature = "std", derive(specta::Type))]
|
#[cfg_attr(feature = "std", derive(specta::Type))]
|
||||||
#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, DynAny, Hash)]
|
#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, DynAny, Hash)]
|
||||||
|
#[repr(i32)] // TODO: Enable Int8 capability for SPRIV so that we don't need this?
|
||||||
pub enum BlendMode {
|
pub enum BlendMode {
|
||||||
#[default]
|
#[default]
|
||||||
// Basic group
|
// Basic group
|
||||||
|
|
@ -173,6 +174,46 @@ impl core::fmt::Display for BlendMode {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn to_primtive_string(blend_mode: &BlendMode) -> &'static str {
|
||||||
|
match blend_mode {
|
||||||
|
BlendMode::Normal => "Normal",
|
||||||
|
|
||||||
|
BlendMode::Multiply => "Multiply",
|
||||||
|
BlendMode::Darken => "Darken",
|
||||||
|
BlendMode::ColorBurn => "ColorBurn",
|
||||||
|
BlendMode::LinearBurn => "LinearBurn",
|
||||||
|
BlendMode::DarkerColor => "DarkerColor",
|
||||||
|
|
||||||
|
BlendMode::Screen => "Screen",
|
||||||
|
BlendMode::Lighten => "Lighten",
|
||||||
|
BlendMode::ColorDodge => "ColorDodge",
|
||||||
|
BlendMode::LinearDodge => "LinearDodge",
|
||||||
|
BlendMode::LighterColor => "LighterColor",
|
||||||
|
|
||||||
|
BlendMode::Overlay => "Overlay",
|
||||||
|
BlendMode::SoftLight => "SoftLight",
|
||||||
|
BlendMode::HardLight => "HardLight",
|
||||||
|
BlendMode::VividLight => "VividLight",
|
||||||
|
BlendMode::LinearLight => "LinearLight",
|
||||||
|
BlendMode::PinLight => "PinLight",
|
||||||
|
BlendMode::HardMix => "HardMix",
|
||||||
|
|
||||||
|
BlendMode::Difference => "Difference",
|
||||||
|
BlendMode::Exclusion => "Exclusion",
|
||||||
|
BlendMode::Subtract => "Subtract",
|
||||||
|
BlendMode::Divide => "Divide",
|
||||||
|
|
||||||
|
BlendMode::Hue => "Hue",
|
||||||
|
BlendMode::Saturation => "Saturation",
|
||||||
|
BlendMode::Color => "Color",
|
||||||
|
BlendMode::Luminosity => "Luminosity",
|
||||||
|
|
||||||
|
BlendMode::InsertRed => "InsertRed",
|
||||||
|
BlendMode::InsertGreen => "InsertGreen",
|
||||||
|
BlendMode::InsertBlue => "InsertBlue",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Default)]
|
#[derive(Debug, Clone, Copy, Default)]
|
||||||
pub struct LuminanceNode<LuminanceCalculation> {
|
pub struct LuminanceNode<LuminanceCalculation> {
|
||||||
luminance_calc: LuminanceCalculation,
|
luminance_calc: LuminanceCalculation,
|
||||||
|
|
@ -410,7 +451,7 @@ pub struct BlendNode<BlendMode, Opacity> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[node_macro::node_fn(BlendNode)]
|
#[node_macro::node_fn(BlendNode)]
|
||||||
fn blend_node(input: (Color, Color), blend_mode: BlendMode, opacity: f64) -> Color {
|
fn blend_node(input: (Color, Color), blend_mode: BlendMode, opacity: f32) -> Color {
|
||||||
let opacity = opacity / 100.;
|
let opacity = opacity / 100.;
|
||||||
|
|
||||||
let (foreground, background) = input;
|
let (foreground, background) = input;
|
||||||
|
|
@ -452,7 +493,7 @@ fn blend_node(input: (Color, Color), blend_mode: BlendMode, opacity: f64) -> Col
|
||||||
BlendMode::InsertBlue => foreground.with_blue(background.b()),
|
BlendMode::InsertBlue => foreground.with_blue(background.b()),
|
||||||
};
|
};
|
||||||
|
|
||||||
background.alpha_blend(target_color.to_associated_alpha(opacity as f32))
|
background.alpha_blend(target_color.to_associated_alpha(opacity))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,19 @@ macro_rules! concrete {
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! concrete_with_name {
|
||||||
|
($type:ty, $name:expr) => {
|
||||||
|
Type::Concrete(TypeDescriptor {
|
||||||
|
id: Some(core::any::TypeId::of::<$type>()),
|
||||||
|
name: Cow::Borrowed($name),
|
||||||
|
size: core::mem::size_of::<$type>(),
|
||||||
|
align: core::mem::align_of::<$type>(),
|
||||||
|
})
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! generic {
|
macro_rules! generic {
|
||||||
($type:ty) => {{
|
($type:ty) => {{
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ pub fn compile_spirv(request: &CompileRequest, compile_dir: Option<&str>, manife
|
||||||
|
|
||||||
println!("calling cargo run!");
|
println!("calling cargo run!");
|
||||||
let non_cargo_env_vars = std::env::vars().filter(|(k, _)| k.starts_with("PATH")).collect::<Vec<_>>();
|
let non_cargo_env_vars = std::env::vars().filter(|(k, _)| k.starts_with("PATH")).collect::<Vec<_>>();
|
||||||
let mut cargo_command = std::process::Command::new("/usr/bin/cargo")
|
let mut cargo_command = std::process::Command::new("cargo")
|
||||||
.arg("run")
|
.arg("run")
|
||||||
.arg("--release")
|
.arg("--release")
|
||||||
.arg("--manifest-path")
|
.arg("--manifest-path")
|
||||||
|
|
|
||||||
|
|
@ -71,7 +71,7 @@ pub fn construct_argument(input: &ShaderInput<()>, position: u32, binding_offset
|
||||||
let line = match input {
|
let line = match input {
|
||||||
ShaderInput::Constant(constant) => format!("#[spirv({})] i{}: {}", constant_attribute(constant), position, constant.ty()),
|
ShaderInput::Constant(constant) => format!("#[spirv({})] i{}: {}", constant_attribute(constant), position, constant.ty()),
|
||||||
ShaderInput::UniformBuffer(_, ty) => {
|
ShaderInput::UniformBuffer(_, ty) => {
|
||||||
format!("#[spirv(uniform, descriptor_set = 0, binding = {})] i{}: &[{}]", position + binding_offset, position, ty,)
|
format!("#[spirv(uniform, descriptor_set = 0, binding = {})] i{}: &{}", position + binding_offset, position, ty,)
|
||||||
}
|
}
|
||||||
ShaderInput::StorageBuffer(_, ty) | ShaderInput::ReadBackBuffer(_, ty) => {
|
ShaderInput::StorageBuffer(_, ty) | ShaderInput::ReadBackBuffer(_, ty) => {
|
||||||
format!("#[spirv(storage_buffer, descriptor_set = 0, binding = {})] i{}: &[{}]", position + binding_offset, position, ty,)
|
format!("#[spirv(storage_buffer, descriptor_set = 0, binding = {})] i{}: &[{}]", position + binding_offset, position, ty,)
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,8 @@ extern crate spirv_std;
|
||||||
//pub mod gpu {
|
//pub mod gpu {
|
||||||
//use super::*;
|
//use super::*;
|
||||||
use spirv_std::spirv;
|
use spirv_std::spirv;
|
||||||
use spirv_std::glam::UVec3;
|
use spirv_std::glam;
|
||||||
|
use spirv_std::glam::{UVec3, Vec2, Mat2, BVec2};
|
||||||
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
#[spirv(compute(threads({{compute_threads}})))]
|
#[spirv(compute(threads({{compute_threads}})))]
|
||||||
|
|
@ -19,6 +20,8 @@ extern crate spirv_std;
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
) {
|
) {
|
||||||
use graphene_core::Node;
|
use graphene_core::Node;
|
||||||
|
use graphene_core::raster::adjustments::{BlendMode, BlendNode};
|
||||||
|
use graphene_core::Color;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
{% for input in input_nodes %}
|
{% for input in input_nodes %}
|
||||||
|
|
@ -34,7 +37,7 @@ extern crate spirv_std;
|
||||||
|
|
||||||
{% for output in output_nodes %}
|
{% for output in output_nodes %}
|
||||||
let v = {{output}}.eval(());
|
let v = {{output}}.eval(());
|
||||||
o{{loop.index0}}[_global_index.x as usize] = v;
|
o{{loop.index0}}[(_global_index.y * i0 + _global_index.x) as usize] = v;
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
// TODO: Write output to buffer
|
// TODO: Write output to buffer
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,22 @@ use std::sync::Arc;
|
||||||
|
|
||||||
type ReadBackFuture = Pin<Box<dyn Future<Output = Result<Vec<u8>>>>>;
|
type ReadBackFuture = Pin<Box<dyn Future<Output = Result<Vec<u8>>>>>;
|
||||||
|
|
||||||
|
pub enum ComputePassDimensions {
|
||||||
|
X(u32),
|
||||||
|
XY(u32, u32),
|
||||||
|
XYZ(u32, u32, u32),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ComputePassDimensions {
|
||||||
|
pub fn get(&self) -> (u32, u32, u32) {
|
||||||
|
match self {
|
||||||
|
ComputePassDimensions::X(x) => (*x, 1, 1),
|
||||||
|
ComputePassDimensions::XY(x, y) => (*x, *y, 1),
|
||||||
|
ComputePassDimensions::XYZ(x, y, z) => (*x, *y, *z),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub trait GpuExecutor {
|
pub trait GpuExecutor {
|
||||||
type ShaderHandle;
|
type ShaderHandle;
|
||||||
type BufferHandle;
|
type BufferHandle;
|
||||||
|
|
@ -22,7 +38,7 @@ pub trait GpuExecutor {
|
||||||
fn create_uniform_buffer<T: ToUniformBuffer>(&self, data: T) -> Result<ShaderInput<Self::BufferHandle>>;
|
fn create_uniform_buffer<T: ToUniformBuffer>(&self, data: T) -> Result<ShaderInput<Self::BufferHandle>>;
|
||||||
fn create_storage_buffer<T: ToStorageBuffer>(&self, data: T, options: StorageBufferOptions) -> Result<ShaderInput<Self::BufferHandle>>;
|
fn create_storage_buffer<T: ToStorageBuffer>(&self, data: T, options: StorageBufferOptions) -> Result<ShaderInput<Self::BufferHandle>>;
|
||||||
fn create_output_buffer(&self, len: usize, ty: Type, cpu_readable: bool) -> Result<ShaderInput<Self::BufferHandle>>;
|
fn create_output_buffer(&self, len: usize, ty: Type, cpu_readable: bool) -> Result<ShaderInput<Self::BufferHandle>>;
|
||||||
fn create_compute_pass(&self, layout: &PipelineLayout<Self>, read_back: Option<Arc<ShaderInput<Self::BufferHandle>>>, instances: u32) -> Result<Self::CommandBuffer>;
|
fn create_compute_pass(&self, layout: &PipelineLayout<Self>, read_back: Option<Arc<ShaderInput<Self::BufferHandle>>>, instances: ComputePassDimensions) -> Result<Self::CommandBuffer>;
|
||||||
fn execute_compute_pipeline(&self, encoder: Self::CommandBuffer) -> Result<()>;
|
fn execute_compute_pipeline(&self, encoder: Self::CommandBuffer) -> Result<()>;
|
||||||
fn read_output_buffer(&self, buffer: Arc<ShaderInput<Self::BufferHandle>>) -> ReadBackFuture;
|
fn read_output_buffer(&self, buffer: Arc<ShaderInput<Self::BufferHandle>>) -> ReadBackFuture;
|
||||||
}
|
}
|
||||||
|
|
@ -129,10 +145,15 @@ pub struct StorageBufferOptions {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait ToUniformBuffer: StaticType {
|
pub trait ToUniformBuffer: StaticType {
|
||||||
type UniformBufferHandle;
|
|
||||||
fn to_bytes(&self) -> Cow<[u8]>;
|
fn to_bytes(&self) -> Cow<[u8]>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T: StaticType + Pod + Zeroable> ToUniformBuffer for T {
|
||||||
|
fn to_bytes(&self) -> Cow<[u8]> {
|
||||||
|
Cow::Owned(bytemuck::bytes_of(self).into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub trait ToStorageBuffer: StaticType {
|
pub trait ToStorageBuffer: StaticType {
|
||||||
fn to_bytes(&self) -> Cow<[u8]>;
|
fn to_bytes(&self) -> Cow<[u8]>;
|
||||||
fn ty(&self) -> Type;
|
fn ty(&self) -> Type;
|
||||||
|
|
@ -233,7 +254,12 @@ pub struct CreateComputePassNode<Executor, Output, Instances> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[node_macro::node_fn(CreateComputePassNode)]
|
#[node_macro::node_fn(CreateComputePassNode)]
|
||||||
fn create_compute_pass_node<E: GpuExecutor + 'input>(layout: PipelineLayout<E>, executor: &'input E, output: ShaderInput<E::BufferHandle>, instances: u32) -> E::CommandBuffer {
|
fn create_compute_pass_node<'any_input, E: 'any_input + GpuExecutor>(
|
||||||
|
layout: PipelineLayout<E>,
|
||||||
|
executor: &'any_input E,
|
||||||
|
output: ShaderInput<E::BufferHandle>,
|
||||||
|
instances: ComputePassDimensions,
|
||||||
|
) -> E::CommandBuffer {
|
||||||
executor.create_compute_pass(&layout, Some(output.into()), instances).unwrap()
|
executor.create_compute_pass(&layout, Some(output.into()), instances).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ use crate::executor::Any;
|
||||||
pub use crate::imaginate_input::{ImaginateMaskStartingFill, ImaginateSamplingMethod, ImaginateStatus};
|
pub use crate::imaginate_input::{ImaginateMaskStartingFill, ImaginateSamplingMethod, ImaginateStatus};
|
||||||
use crate::proto::{Any as DAny, FutureAny};
|
use crate::proto::{Any as DAny, FutureAny};
|
||||||
|
|
||||||
use graphene_core::raster::{BlendMode, LuminanceCalculation};
|
use graphene_core::raster::{to_primtive_string, BlendMode, LuminanceCalculation};
|
||||||
use graphene_core::{Color, Node, Type};
|
use graphene_core::{Color, Node, Type};
|
||||||
|
|
||||||
pub use dyn_any::StaticType;
|
pub use dyn_any::StaticType;
|
||||||
|
|
@ -185,10 +185,11 @@ impl<'a> TaggedValue {
|
||||||
match self {
|
match self {
|
||||||
TaggedValue::None => "()".to_string(),
|
TaggedValue::None => "()".to_string(),
|
||||||
TaggedValue::String(x) => format!("\"{}\"", x),
|
TaggedValue::String(x) => format!("\"{}\"", x),
|
||||||
TaggedValue::U32(x) => x.to_string(),
|
TaggedValue::U32(x) => x.to_string() + "_u32",
|
||||||
TaggedValue::F32(x) => x.to_string(),
|
TaggedValue::F32(x) => x.to_string() + "_f32",
|
||||||
TaggedValue::F64(x) => x.to_string(),
|
TaggedValue::F64(x) => x.to_string() + "_f64",
|
||||||
TaggedValue::Bool(x) => x.to_string(),
|
TaggedValue::Bool(x) => x.to_string(),
|
||||||
|
TaggedValue::BlendMode(blend_mode) => "BlendMode::".to_string() + to_primtive_string(blend_mode),
|
||||||
_ => panic!("Cannot convert to primitive string"),
|
_ => panic!("Cannot convert to primitive string"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
use glam::UVec3;
|
use glam::{DAffine2, DMat2, DVec2, Mat2, UVec3, Vec2};
|
||||||
use gpu_executor::{Bindgroup, PipelineLayout, StorageBufferOptions};
|
use gpu_executor::{Bindgroup, ComputePassDimensions, PipelineLayout, StorageBufferOptions};
|
||||||
use gpu_executor::{GpuExecutor, ShaderIO, ShaderInput};
|
use gpu_executor::{GpuExecutor, ShaderIO, ShaderInput};
|
||||||
use graph_craft::document::value::TaggedValue;
|
use graph_craft::document::value::TaggedValue;
|
||||||
use graph_craft::document::*;
|
use graph_craft::document::*;
|
||||||
use graph_craft::proto::*;
|
use graph_craft::proto::*;
|
||||||
|
use graphene_core::raster::bbox::{AxisAlignedBbox, Bbox};
|
||||||
use graphene_core::raster::*;
|
use graphene_core::raster::*;
|
||||||
use graphene_core::value::ValueNode;
|
|
||||||
use graphene_core::*;
|
use graphene_core::*;
|
||||||
use wgpu_executor::NewExecutor;
|
use wgpu_executor::NewExecutor;
|
||||||
|
|
||||||
|
|
@ -58,7 +58,7 @@ async fn map_gpu(image: ImageFrame<Color>, node: DocumentNode) -> ImageFrame<Col
|
||||||
nodes: [
|
nodes: [
|
||||||
DocumentNode {
|
DocumentNode {
|
||||||
name: "Slice".into(),
|
name: "Slice".into(),
|
||||||
inputs: vec![NodeInput::Inline(InlineRust::new("i0[_global_index.x as usize]".into(), concrete![Color]))],
|
inputs: vec![NodeInput::Inline(InlineRust::new("i1[(_global_index.y * i0 + _global_index.x) as usize]".into(), concrete![Color]))],
|
||||||
implementation: DocumentNodeImplementation::Unresolved("graphene_core::value::CopiedNode".into()),
|
implementation: DocumentNodeImplementation::Unresolved("graphene_core::value::CopiedNode".into()),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
|
|
@ -108,10 +108,11 @@ async fn map_gpu(image: ImageFrame<Color>, node: DocumentNode) -> ImageFrame<Col
|
||||||
log::debug!("compiling shader");
|
log::debug!("compiling shader");
|
||||||
let shader = compilation_client::compile(
|
let shader = compilation_client::compile(
|
||||||
proto_networks,
|
proto_networks,
|
||||||
vec![concrete!(Color)], //, concrete!(u32)],
|
vec![concrete!(u32), concrete!(Color)], //, concrete!(u32)],
|
||||||
vec![concrete!(Color)],
|
vec![concrete!(Color)],
|
||||||
ShaderIO {
|
ShaderIO {
|
||||||
inputs: vec![
|
inputs: vec![
|
||||||
|
ShaderInput::UniformBuffer((), concrete!(u32)),
|
||||||
ShaderInput::StorageBuffer((), concrete!(Color)),
|
ShaderInput::StorageBuffer((), concrete!(Color)),
|
||||||
//ShaderInput::Constant(gpu_executor::GPUConstant::GlobalInvocationId),
|
//ShaderInput::Constant(gpu_executor::GPUConstant::GlobalInvocationId),
|
||||||
ShaderInput::OutputBuffer((), concrete!(Color)),
|
ShaderInput::OutputBuffer((), concrete!(Color)),
|
||||||
|
|
@ -122,11 +123,11 @@ async fn map_gpu(image: ImageFrame<Color>, node: DocumentNode) -> ImageFrame<Col
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
//return ImageFrame::empty();
|
//return ImageFrame::empty();
|
||||||
let len = image.image.data.len();
|
let len: usize = image.image.data.len();
|
||||||
log::debug!("instances: {}", len);
|
|
||||||
|
|
||||||
let executor = NewExecutor::new().await.unwrap();
|
let executor = NewExecutor::new().await.unwrap();
|
||||||
log::debug!("creating buffer");
|
log::debug!("creating buffer");
|
||||||
|
let width_uniform = executor.create_uniform_buffer(image.image.width).unwrap();
|
||||||
let storage_buffer = executor
|
let storage_buffer = executor
|
||||||
.create_storage_buffer(
|
.create_storage_buffer(
|
||||||
image.image.data.clone(),
|
image.image.data.clone(),
|
||||||
|
|
@ -138,6 +139,7 @@ async fn map_gpu(image: ImageFrame<Color>, node: DocumentNode) -> ImageFrame<Col
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
let width_uniform = Arc::new(width_uniform);
|
||||||
let storage_buffer = Arc::new(storage_buffer);
|
let storage_buffer = Arc::new(storage_buffer);
|
||||||
let output_buffer = executor.create_output_buffer(len, concrete!(Color), false).unwrap();
|
let output_buffer = executor.create_output_buffer(len, concrete!(Color), false).unwrap();
|
||||||
let output_buffer = Arc::new(output_buffer);
|
let output_buffer = Arc::new(output_buffer);
|
||||||
|
|
@ -145,7 +147,7 @@ async fn map_gpu(image: ImageFrame<Color>, node: DocumentNode) -> ImageFrame<Col
|
||||||
let readback_buffer = Arc::new(readback_buffer);
|
let readback_buffer = Arc::new(readback_buffer);
|
||||||
log::debug!("created buffer");
|
log::debug!("created buffer");
|
||||||
let bind_group = Bindgroup {
|
let bind_group = Bindgroup {
|
||||||
buffers: vec![storage_buffer.clone()],
|
buffers: vec![width_uniform.clone(), storage_buffer.clone()],
|
||||||
};
|
};
|
||||||
|
|
||||||
let shader = gpu_executor::Shader {
|
let shader = gpu_executor::Shader {
|
||||||
|
|
@ -164,7 +166,9 @@ async fn map_gpu(image: ImageFrame<Color>, node: DocumentNode) -> ImageFrame<Col
|
||||||
output_buffer: output_buffer.clone(),
|
output_buffer: output_buffer.clone(),
|
||||||
};
|
};
|
||||||
log::debug!("created pipeline");
|
log::debug!("created pipeline");
|
||||||
let compute_pass = executor.create_compute_pass(&pipeline, Some(readback_buffer.clone()), len as u32).unwrap();
|
let compute_pass = executor
|
||||||
|
.create_compute_pass(&pipeline, Some(readback_buffer.clone()), ComputePassDimensions::XY(image.image.width, image.image.height))
|
||||||
|
.unwrap();
|
||||||
executor.execute_compute_pipeline(compute_pass).unwrap();
|
executor.execute_compute_pipeline(compute_pass).unwrap();
|
||||||
log::debug!("executed pipeline");
|
log::debug!("executed pipeline");
|
||||||
log::debug!("reading buffer");
|
log::debug!("reading buffer");
|
||||||
|
|
@ -243,3 +247,183 @@ fn map_gpu_single_image(input: Image<Color>, node: String) -> Image<Color> {
|
||||||
Image { data, ..input }
|
Image { data, ..input }
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub struct BlendGpuImageNode<Background, B, O> {
|
||||||
|
background: Background,
|
||||||
|
blend_mode: B,
|
||||||
|
opacity: O,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[node_macro::node_fn(BlendGpuImageNode)]
|
||||||
|
async fn blend_gpu_image(foreground: ImageFrame<Color>, background: ImageFrame<Color>, blend_mode: BlendMode, opacity: f32) -> ImageFrame<Color> {
|
||||||
|
let foreground_size = DVec2::new(foreground.image.width as f64, foreground.image.height as f64);
|
||||||
|
let background_size = DVec2::new(background.image.width as f64, background.image.height as f64);
|
||||||
|
// Transforms a point from the background image to the forground image
|
||||||
|
let bg_to_fg = DAffine2::from_scale(foreground_size) * foreground.transform.inverse() * background.transform * DAffine2::from_scale(1. / background_size);
|
||||||
|
|
||||||
|
let transform_matrix: Mat2 = bg_to_fg.matrix2.as_mat2();
|
||||||
|
let translation: Vec2 = bg_to_fg.translation.as_vec2();
|
||||||
|
|
||||||
|
log::debug!("Executing gpu blend node!");
|
||||||
|
let compiler = graph_craft::executor::Compiler {};
|
||||||
|
|
||||||
|
let network = NodeNetwork {
|
||||||
|
inputs: vec![],
|
||||||
|
outputs: vec![NodeOutput::new(0, 0)],
|
||||||
|
nodes: [DocumentNode {
|
||||||
|
name: "BlendOp".into(),
|
||||||
|
inputs: vec![NodeInput::Inline(InlineRust::new(
|
||||||
|
format!(
|
||||||
|
r#"graphene_core::raster::adjustments::BlendNode::new(
|
||||||
|
graphene_core::value::CopiedNode::new({}),
|
||||||
|
graphene_core::value::CopiedNode::new({}),
|
||||||
|
).eval((
|
||||||
|
{{
|
||||||
|
let bg_point = Vec2::new(_global_index.x as f32, _global_index.y as f32);
|
||||||
|
let fg_point = (*i4) * bg_point + (*i5);
|
||||||
|
|
||||||
|
if !((fg_point.cmpge(Vec2::ZERO) & bg_point.cmpge(Vec2::ZERO)) == BVec2::new(true, true)) {{
|
||||||
|
Color::from_rgbaf32_unchecked(0.0, 0.0, 0.0, 0.0)
|
||||||
|
}} else {{
|
||||||
|
i2[((fg_point.y as u32) * i3 + (fg_point.x as u32)) as usize]
|
||||||
|
}}
|
||||||
|
}},
|
||||||
|
i1[(_global_index.y * i0 + _global_index.x) as usize],
|
||||||
|
))"#,
|
||||||
|
TaggedValue::BlendMode(blend_mode).to_primitive_string(),
|
||||||
|
TaggedValue::F32(opacity).to_primitive_string(),
|
||||||
|
),
|
||||||
|
concrete![Color],
|
||||||
|
))],
|
||||||
|
implementation: DocumentNodeImplementation::Unresolved("graphene_core::value::CopiedNode".into()),
|
||||||
|
..Default::default()
|
||||||
|
}]
|
||||||
|
.into_iter()
|
||||||
|
.enumerate()
|
||||||
|
.map(|(i, n)| (i as u64, n))
|
||||||
|
.collect(),
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
log::debug!("compiling network");
|
||||||
|
let proto_networks = compiler.compile(network.clone(), true).collect();
|
||||||
|
log::debug!("compiling shader");
|
||||||
|
|
||||||
|
let shader = compilation_client::compile(
|
||||||
|
proto_networks,
|
||||||
|
vec![
|
||||||
|
concrete!(u32),
|
||||||
|
concrete!(Color),
|
||||||
|
concrete!(Color),
|
||||||
|
concrete!(u32),
|
||||||
|
concrete_with_name!(Mat2, "Mat2"),
|
||||||
|
concrete_with_name!(Vec2, "Vec2"),
|
||||||
|
],
|
||||||
|
vec![concrete!(Color)],
|
||||||
|
ShaderIO {
|
||||||
|
inputs: vec![
|
||||||
|
ShaderInput::UniformBuffer((), concrete!(u32)), // width of the output image
|
||||||
|
ShaderInput::StorageBuffer((), concrete!(Color)), // background image
|
||||||
|
ShaderInput::StorageBuffer((), concrete!(Color)), // foreground image
|
||||||
|
ShaderInput::UniformBuffer((), concrete!(u32)), // width of the foreground image
|
||||||
|
ShaderInput::UniformBuffer((), concrete_with_name!(Mat2, "Mat2")), // bg_to_fg.matrix2
|
||||||
|
ShaderInput::UniformBuffer((), concrete_with_name!(Vec2, "Vec2")), // bg_to_fg.translation
|
||||||
|
ShaderInput::OutputBuffer((), concrete!(Color)),
|
||||||
|
],
|
||||||
|
output: ShaderInput::OutputBuffer((), concrete!(Color)),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
let len = background.image.data.len();
|
||||||
|
|
||||||
|
let executor = NewExecutor::new()
|
||||||
|
.await
|
||||||
|
.expect("Failed to create wgpu executor. Please make sure that webgpu is enabled for your browser.");
|
||||||
|
log::debug!("creating buffer");
|
||||||
|
let width_uniform = executor.create_uniform_buffer(background.image.width).unwrap();
|
||||||
|
let bg_storage_buffer = executor
|
||||||
|
.create_storage_buffer(
|
||||||
|
background.image.data.clone(),
|
||||||
|
StorageBufferOptions {
|
||||||
|
cpu_writable: false,
|
||||||
|
gpu_writable: true,
|
||||||
|
cpu_readable: false,
|
||||||
|
storage: true,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
let fg_storage_buffer = executor
|
||||||
|
.create_storage_buffer(
|
||||||
|
foreground.image.data.clone(),
|
||||||
|
StorageBufferOptions {
|
||||||
|
cpu_writable: false,
|
||||||
|
gpu_writable: true,
|
||||||
|
cpu_readable: false,
|
||||||
|
storage: true,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
let fg_width_uniform = executor.create_uniform_buffer(foreground.image.width).unwrap();
|
||||||
|
let transform_uniform = executor.create_uniform_buffer(transform_matrix).unwrap();
|
||||||
|
let translation_uniform = executor.create_uniform_buffer(translation).unwrap();
|
||||||
|
let width_uniform = Arc::new(width_uniform);
|
||||||
|
let bg_storage_buffer = Arc::new(bg_storage_buffer);
|
||||||
|
let fg_storage_buffer = Arc::new(fg_storage_buffer);
|
||||||
|
let fg_width_uniform = Arc::new(fg_width_uniform);
|
||||||
|
let transform_uniform = Arc::new(transform_uniform);
|
||||||
|
let translation_uniform = Arc::new(translation_uniform);
|
||||||
|
let output_buffer = executor.create_output_buffer(len, concrete!(Color), false).unwrap();
|
||||||
|
let output_buffer = Arc::new(output_buffer);
|
||||||
|
let readback_buffer = executor.create_output_buffer(len, concrete!(Color), true).unwrap();
|
||||||
|
let readback_buffer = Arc::new(readback_buffer);
|
||||||
|
log::debug!("created buffer");
|
||||||
|
let bind_group = Bindgroup {
|
||||||
|
buffers: vec![
|
||||||
|
width_uniform.clone(),
|
||||||
|
bg_storage_buffer.clone(),
|
||||||
|
fg_storage_buffer.clone(),
|
||||||
|
fg_width_uniform.clone(),
|
||||||
|
transform_uniform.clone(),
|
||||||
|
translation_uniform.clone(),
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
let shader = gpu_executor::Shader {
|
||||||
|
source: shader.spirv_binary.into(),
|
||||||
|
name: "gpu::eval",
|
||||||
|
io: shader.io,
|
||||||
|
};
|
||||||
|
log::debug!("loading shader");
|
||||||
|
log::debug!("shader: {:?}", shader.source);
|
||||||
|
let shader = executor.load_shader(shader).unwrap();
|
||||||
|
log::debug!("loaded shader");
|
||||||
|
let pipeline = PipelineLayout {
|
||||||
|
shader,
|
||||||
|
entry_point: "eval".to_string(),
|
||||||
|
bind_group,
|
||||||
|
output_buffer: output_buffer.clone(),
|
||||||
|
};
|
||||||
|
log::debug!("created pipeline");
|
||||||
|
let compute_pass = executor
|
||||||
|
.create_compute_pass(
|
||||||
|
&pipeline,
|
||||||
|
Some(readback_buffer.clone()),
|
||||||
|
ComputePassDimensions::XY(background.image.width as u32, background.image.height as u32),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
executor.execute_compute_pipeline(compute_pass).unwrap();
|
||||||
|
log::debug!("executed pipeline");
|
||||||
|
log::debug!("reading buffer");
|
||||||
|
let result = executor.read_output_buffer(readback_buffer).await.unwrap();
|
||||||
|
let colors = bytemuck::pod_collect_to_vec::<u8, Color>(result.as_slice());
|
||||||
|
|
||||||
|
ImageFrame {
|
||||||
|
image: Image {
|
||||||
|
data: colors,
|
||||||
|
width: background.image.width,
|
||||||
|
height: background.image.height,
|
||||||
|
},
|
||||||
|
transform: background.transform,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -223,6 +223,26 @@ fn node_registry() -> HashMap<NodeIdentifier, HashMap<NodeIOTypes, NodeConstruct
|
||||||
},
|
},
|
||||||
NodeIOTypes::new(concrete!(ImageFrame<Color>), concrete!(ImageFrame<Color>), vec![value_fn!(DocumentNode)]),
|
NodeIOTypes::new(concrete!(ImageFrame<Color>), concrete!(ImageFrame<Color>), vec![value_fn!(DocumentNode)]),
|
||||||
)],
|
)],
|
||||||
|
#[cfg(feature = "gpu")]
|
||||||
|
vec![(
|
||||||
|
NodeIdentifier::new("graphene_std::executor::BlendGpuImageNode<_, _, _>"),
|
||||||
|
|args| {
|
||||||
|
Box::pin(async move {
|
||||||
|
let background: DowncastBothNode<(), ImageFrame<Color>> = DowncastBothNode::new(args[0]);
|
||||||
|
let blend_mode: DowncastBothNode<(), BlendMode> = DowncastBothNode::new(args[1]);
|
||||||
|
let opacity: DowncastBothNode<(), f32> = DowncastBothNode::new(args[2]);
|
||||||
|
let node = graphene_std::executor::BlendGpuImageNode::new(background, blend_mode, opacity);
|
||||||
|
let any: DynAnyNode<ImageFrame<Color>, _, _> = graphene_std::any::DynAnyNode::new(graphene_core::value::ValueNode::new(node));
|
||||||
|
|
||||||
|
Box::pin(any) as TypeErasedPinned
|
||||||
|
})
|
||||||
|
},
|
||||||
|
NodeIOTypes::new(
|
||||||
|
concrete!(ImageFrame<Color>),
|
||||||
|
concrete!(ImageFrame<Color>),
|
||||||
|
vec![value_fn!(ImageFrame<Color>), value_fn!(BlendMode), value_fn!(f32)],
|
||||||
|
),
|
||||||
|
)],
|
||||||
vec![(
|
vec![(
|
||||||
NodeIdentifier::new("graphene_core::structural::ComposeNode<_, _, _>"),
|
NodeIdentifier::new("graphene_core::structural::ComposeNode<_, _, _>"),
|
||||||
|args| {
|
|args| {
|
||||||
|
|
@ -326,7 +346,7 @@ fn node_registry() -> HashMap<NodeIdentifier, HashMap<NodeIOTypes, NodeConstruct
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
let image: DowncastBothNode<(), ImageFrame<Color>> = DowncastBothNode::new(args[0]);
|
let image: DowncastBothNode<(), ImageFrame<Color>> = DowncastBothNode::new(args[0]);
|
||||||
let blend_mode: DowncastBothNode<(), BlendMode> = DowncastBothNode::new(args[1]);
|
let blend_mode: DowncastBothNode<(), BlendMode> = DowncastBothNode::new(args[1]);
|
||||||
let opacity: DowncastBothNode<(), f64> = DowncastBothNode::new(args[2]);
|
let opacity: DowncastBothNode<(), f32> = DowncastBothNode::new(args[2]);
|
||||||
let blend_node = graphene_core::raster::BlendNode::new(CopiedNode::new(blend_mode.eval(()).await), CopiedNode::new(opacity.eval(()).await));
|
let blend_node = graphene_core::raster::BlendNode::new(CopiedNode::new(blend_mode.eval(()).await), CopiedNode::new(opacity.eval(()).await));
|
||||||
let node = graphene_std::raster::BlendImageNode::new(image, FutureWrapperNode::new(ValueNode::new(blend_node)));
|
let node = graphene_std::raster::BlendImageNode::new(image, FutureWrapperNode::new(ValueNode::new(blend_node)));
|
||||||
let any: DynAnyNode<ImageFrame<Color>, _, _> = graphene_std::any::DynAnyNode::new(graphene_core::value::ValueNode::new(node));
|
let any: DynAnyNode<ImageFrame<Color>, _, _> = graphene_std::any::DynAnyNode::new(graphene_core::value::ValueNode::new(node));
|
||||||
|
|
@ -336,7 +356,7 @@ fn node_registry() -> HashMap<NodeIdentifier, HashMap<NodeIOTypes, NodeConstruct
|
||||||
NodeIOTypes::new(
|
NodeIOTypes::new(
|
||||||
concrete!(ImageFrame<Color>),
|
concrete!(ImageFrame<Color>),
|
||||||
concrete!(ImageFrame<Color>),
|
concrete!(ImageFrame<Color>),
|
||||||
vec![value_fn!(ImageFrame<Color>), value_fn!(BlendMode), value_fn!(f64)],
|
vec![value_fn!(ImageFrame<Color>), value_fn!(BlendMode), value_fn!(f32)],
|
||||||
),
|
),
|
||||||
)],
|
)],
|
||||||
raster_node!(graphene_core::raster::GrayscaleNode<_, _, _, _, _, _, _>, params: [Color, f64, f64, f64, f64, f64, f64]),
|
raster_node!(graphene_core::raster::GrayscaleNode<_, _, _, _, _, _, _>, params: [Color, f64, f64, f64, f64, f64, f64]),
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ mod executor;
|
||||||
|
|
||||||
pub use context::Context;
|
pub use context::Context;
|
||||||
pub use executor::GpuExecutor;
|
pub use executor::GpuExecutor;
|
||||||
use gpu_executor::{Shader, ShaderInput, StorageBufferOptions, ToStorageBuffer, ToUniformBuffer};
|
use gpu_executor::{ComputePassDimensions, Shader, ShaderInput, StorageBufferOptions, ToStorageBuffer, ToUniformBuffer};
|
||||||
use graph_craft::Type;
|
use graph_craft::Type;
|
||||||
|
|
||||||
use anyhow::{bail, Result};
|
use anyhow::{bail, Result};
|
||||||
|
|
@ -83,7 +83,7 @@ impl gpu_executor::GpuExecutor for NewExecutor {
|
||||||
};
|
};
|
||||||
Ok(buffer)
|
Ok(buffer)
|
||||||
}
|
}
|
||||||
fn create_compute_pass(&self, layout: &gpu_executor::PipelineLayout<Self>, read_back: Option<Arc<ShaderInput<Self::BufferHandle>>>, instances: u32) -> Result<CommandBuffer> {
|
fn create_compute_pass(&self, layout: &gpu_executor::PipelineLayout<Self>, read_back: Option<Arc<ShaderInput<Self::BufferHandle>>>, instances: ComputePassDimensions) -> Result<CommandBuffer> {
|
||||||
let compute_pipeline = self.context.device.create_compute_pipeline(&wgpu::ComputePipelineDescriptor {
|
let compute_pipeline = self.context.device.create_compute_pipeline(&wgpu::ComputePipelineDescriptor {
|
||||||
label: None,
|
label: None,
|
||||||
layout: None,
|
layout: None,
|
||||||
|
|
@ -113,11 +113,12 @@ impl gpu_executor::GpuExecutor for NewExecutor {
|
||||||
|
|
||||||
let mut encoder = self.context.device.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None });
|
let mut encoder = self.context.device.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None });
|
||||||
{
|
{
|
||||||
|
let dimensions = instances.get();
|
||||||
let mut cpass = encoder.begin_compute_pass(&wgpu::ComputePassDescriptor { label: None });
|
let mut cpass = encoder.begin_compute_pass(&wgpu::ComputePassDescriptor { label: None });
|
||||||
cpass.set_pipeline(&compute_pipeline);
|
cpass.set_pipeline(&compute_pipeline);
|
||||||
cpass.set_bind_group(0, &bind_group, &[]);
|
cpass.set_bind_group(0, &bind_group, &[]);
|
||||||
cpass.insert_debug_marker("compute node network evaluation");
|
cpass.insert_debug_marker("compute node network evaluation");
|
||||||
cpass.dispatch_workgroups(instances, 1, 1); // Number of cells to run, the (x,y,z) size of item being processed
|
cpass.dispatch_workgroups(dimensions.0, dimensions.1, dimensions.2); // Number of cells to run, the (x,y,z) size of item being processed
|
||||||
}
|
}
|
||||||
// Sets adds copy operation to command encoder.
|
// Sets adds copy operation to command encoder.
|
||||||
// Will copy data from storage buffer on GPU to staging buffer on CPU.
|
// Will copy data from storage buffer on GPU to staging buffer on CPU.
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue