Only dispatch each workgroup not pixel

This commit is contained in:
Dennis Kobert 2023-06-26 21:08:43 +02:00 committed by Keavon Chambers
parent 215589ff49
commit edb33e0c82
8 changed files with 1076 additions and 75 deletions

View file

@ -335,11 +335,11 @@ fn hue_shift_color_node(color: Color, hue_shift: f32, saturation_shift: f32, lig
let [hue, saturation, lightness, alpha] = color.to_hsla();
let color = Color::from_hsla(
(hue + hue_shift as f32 / 360.) % 1.,
(hue + hue_shift / 360.) % 1.,
// TODO: Improve the way saturation works (it's slightly off)
(saturation + saturation_shift as f32 / 100.).clamp(0., 1.),
(saturation + saturation_shift / 100.).clamp(0., 1.),
// TODO: Fix the way lightness works (it's very off)
(lightness + lightness_shift as f32 / 100.).clamp(0., 1.),
(lightness + lightness_shift / 100.).clamp(0., 1.),
alpha,
);

View file

@ -202,7 +202,7 @@ pub fn serialize_gpu(networks: &[ProtoNetwork], io: &ShaderIO) -> anyhow::Result
context.insert("input_nodes", &input_nodes);
context.insert("output_nodes", &output_nodes);
context.insert("nodes", &nodes);
context.insert("compute_threads", &64);
context.insert("compute_threads", "12, 8");
Ok(tera.render("spirv", &context)?)
}

View file

@ -357,12 +357,23 @@ where
/// A struct representing a compute pipeline.
pub struct PipelineLayout<E: GpuExecutor + ?Sized> {
pub shader: E::ShaderHandle,
pub shader: Arc<E::ShaderHandle>,
pub entry_point: String,
pub bind_group: Bindgroup<E>,
pub bind_group: Arc<Bindgroup<E>>,
pub output_buffer: Arc<ShaderInput<E>>,
}
impl<E: GpuExecutor + ?Sized> Clone for PipelineLayout<E> {
fn clone(&self) -> Self {
Self {
shader: self.shader.clone(),
entry_point: self.entry_point.clone(),
bind_group: self.bind_group.clone(),
output_buffer: self.output_buffer.clone(),
}
}
}
unsafe impl<E: GpuExecutor + ?Sized + StaticType> StaticType for PipelineLayout<E>
where
E::Static: GpuExecutor,
@ -457,9 +468,9 @@ pub struct CreatePipelineLayoutNode<_E, EntryPoint, Bindgroup, OutputBuffer> {
#[node_macro::node_fn(CreatePipelineLayoutNode<_E>)]
async fn create_pipeline_layout_node<_E: GpuExecutor>(shader: _E::ShaderHandle, entry_point: String, bind_group: Bindgroup<_E>, output_buffer: Arc<ShaderInput<_E>>) -> PipelineLayout<_E> {
PipelineLayout {
shader,
shader: shader.into(),
entry_point,
bind_group,
bind_group: bind_group.into(),
output_buffer,
}
}

View file

@ -44,7 +44,7 @@ async fn main() -> Result<(), Box<dyn Error>> {
let device = application_io.gpu_executor().unwrap().context.device.clone();
std::thread::spawn(move || loop {
std::thread::sleep(std::time::Duration::from_millis(1));
std::thread::sleep(std::time::Duration::from_nanos(1));
device.poll(wgpu::Maintain::Poll);
});

View file

@ -310,7 +310,7 @@
],
"outputs": [
{
"node_id": 2,
"node_id": 1,
"node_output_index": 0
}
],
@ -341,39 +341,6 @@
},
"path": null
},
"2": {
"name": "Cache",
"inputs": [
{
"ShortCircut": {
"Concrete": {
"name": "()",
"size": 0,
"align": 1
}
}
},
{
"Node": {
"node_id": 1,
"output_index": 0,
"lambda": false
}
}
],
"implementation": {
"Unresolved": {
"name": "graphene_core::memo::MemoNode<_, _>"
}
},
"metadata": {
"position": [
0,
0
]
},
"path": null
},
"1": {
"name": "Upload Texture",
"inputs": [

File diff suppressed because one or more lines are too long

View file

@ -8,6 +8,8 @@ use graphene_core::raster::*;
use graphene_core::*;
use wgpu_executor::WgpuExecutor;
use std::cell::RefCell;
use std::collections::HashMap;
use std::sync::Arc;
use crate::wasm_application_io::WasmApplicationIo;
@ -42,11 +44,69 @@ async fn compile_gpu(node: &'input DocumentNode, mut typing_context: TypingConte
pub struct MapGpuNode<Node, EditorApi> {
node: Node,
editor_api: EditorApi,
cache: RefCell<HashMap<String, ComputePass<WgpuExecutor>>>,
}
#[node_macro::node_fn(MapGpuNode)]
struct ComputePass<T: GpuExecutor> {
pipeline_layout: PipelineLayout<T>,
readback_buffer: Option<Arc<ShaderInput<T>>>,
}
impl<T: GpuExecutor> Clone for ComputePass<T> {
fn clone(&self) -> Self {
Self {
pipeline_layout: self.pipeline_layout.clone(),
readback_buffer: self.readback_buffer.clone(),
}
}
}
#[node_macro::node_impl(MapGpuNode)]
async fn map_gpu<'a: 'input>(image: ImageFrame<Color>, node: DocumentNode, editor_api: graphene_core::application_io::EditorApi<'a, WasmApplicationIo>) -> ImageFrame<Color> {
log::debug!("Executing gpu node");
let executor = &editor_api.application_io.gpu_executor.as_ref().unwrap();
// TODO: The cache should be based on the network topology not the node name
let compute_pass_descriptor = self
.cache
.borrow_mut()
.entry(node.name.clone())
.or_insert_with(|| futures::executor::block_on(create_compute_pass_descriptor(node, &image, executor)))
.clone();
let compute_pass = executor
.create_compute_pass(
&compute_pass_descriptor.pipeline_layout,
compute_pass_descriptor.readback_buffer.clone(),
ComputePassDimensions::XY(image.image.width / 12 + 1, image.image.height / 8 + 1),
)
.unwrap();
executor.execute_compute_pipeline(compute_pass).unwrap();
log::error!("executed pipeline");
log::debug!("reading buffer");
let result = executor.read_output_buffer(compute_pass_descriptor.readback_buffer.clone().unwrap()).await.unwrap();
let colors = bytemuck::pod_collect_to_vec::<u8, Color>(result.as_slice());
ImageFrame {
image: Image {
data: colors,
width: image.image.width,
height: image.image.height,
},
transform: image.transform,
}
}
impl<Node, EditorApi> MapGpuNode<Node, EditorApi> {
pub fn new(node: Node, editor_api: EditorApi) -> Self {
Self {
node,
editor_api,
cache: RefCell::new(HashMap::new()),
}
}
}
async fn create_compute_pass_descriptor(node: DocumentNode, image: &ImageFrame<Color>, executor: &&WgpuExecutor) -> ComputePass<WgpuExecutor> {
let compiler = graph_craft::graphene_compiler::Compiler {};
let inner_network = NodeNetwork::value_network(node);
@ -68,7 +128,7 @@ async fn map_gpu<'a: 'input>(image: ImageFrame<Color>, node: DocumentNode, edito
implementation: DocumentNodeImplementation::Unresolved("graphene_core::value::CopiedNode".into()),
..Default::default()
},*/
/*
/*
DocumentNode {
name: "GetNode".into(),
inputs: vec![NodeInput::node(1, 0), NodeInput::node(0, 0)],
@ -124,8 +184,6 @@ async fn map_gpu<'a: 'input>(image: ImageFrame<Color>, node: DocumentNode, edito
//return ImageFrame::empty();
let len: usize = image.image.data.len();
let executor = &editor_api.application_io.gpu_executor.as_ref().unwrap();
/*
let canvas = editor_api.application_io.create_surface();
@ -175,36 +233,18 @@ async fn map_gpu<'a: 'input>(image: ImageFrame<Color>, node: DocumentNode, edito
let shader = executor.load_shader(shader).unwrap();
log::debug!("loaded shader");
let pipeline = PipelineLayout {
shader,
shader: shader.into(),
entry_point: "eval".to_string(),
bind_group,
bind_group: bind_group.into(),
output_buffer: output_buffer.clone(),
};
log::debug!("created pipeline");
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();
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: image.image.width,
height: image.image.height,
},
transform: image.transform,
}
/*
let executor: GpuExecutor = GpuExecutor::new(Context::new().await.unwrap(), shader.into(), "gpu::eval".into()).unwrap();
let data: Vec<_> = input.into_iter().collect();
let result = executor.execute(Box::new(data)).unwrap();
let result = dyn_any::downcast::<Vec<_O>>(result).unwrap();
*result
*/
let compute_pass_descriptor = ComputePass {
pipeline_layout: pipeline,
readback_buffer: Some(readback_buffer.clone()),
};
compute_pass_descriptor
}
/*
#[node_macro::node_fn(MapGpuNode)]
@ -414,9 +454,9 @@ async fn blend_gpu_image(foreground: ImageFrame<Color>, background: ImageFrame<C
let shader = executor.load_shader(shader).unwrap();
log::debug!("loaded shader");
let pipeline = PipelineLayout {
shader,
shader: shader.into(),
entry_point: "eval".to_string(),
bind_group,
bind_group: bind_group.into(),
output_buffer: output_buffer.clone(),
};
log::debug!("created pipeline");

View file

@ -253,7 +253,7 @@ impl gpu_executor::GpuExecutor for WgpuExecutor {
entries: entries.as_slice(),
});
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: Some("compute encoder") });
{
let dimensions = instances.get();
let mut cpass = encoder.begin_compute_pass(&wgpu::ComputePassDescriptor { label: None });