diff --git a/desktop/src/render/state.rs b/desktop/src/render/state.rs index 2106446204..3958b8cd3c 100644 --- a/desktop/src/render/state.rs +++ b/desktop/src/render/state.rs @@ -1,7 +1,7 @@ use wgpu::PresentMode; use crate::window::Window; -use crate::wrapper::{WgpuContext, WgpuCurrentSurfaceTexture, WgpuExecutor, WgpuSurface}; +use crate::wrapper::{Texture, WgpuContext, WgpuCurrentSurfaceTexture, WgpuExecutor, WgpuSurface}; #[derive(derivative::Derivative)] #[derivative(Debug)] @@ -10,14 +10,14 @@ pub(crate) struct RenderState { executor: WgpuExecutor, config: wgpu::SurfaceConfiguration, render_pipeline: wgpu::RenderPipeline, - transparent_texture: std::sync::Arc, + transparent_texture: Texture, sampler: wgpu::Sampler, desired_width: u32, desired_height: u32, viewport_scale: [f32; 2], viewport_offset: [f32; 2], - viewport_texture: Option>, - overlays_texture: Option>, + viewport_texture: Option, + overlays_texture: Option, ui_texture: Option, bind_group: Option, #[derivative(Debug = "ignore")] @@ -46,8 +46,8 @@ impl RenderState { surface.configure(&context.device, &config); - let transparent_texture = std::sync::Arc::new(context.device.create_texture(&wgpu::TextureDescriptor { - label: Some("Transparent Texture"), + let transparent_texture = Texture::from(context.device.create_texture(&wgpu::TextureDescriptor { + label: Some("transparent_fallback"), size: wgpu::Extent3d { width: 1, height: 1, @@ -193,7 +193,7 @@ impl RenderState { self.surface_outdated = true; } - pub(crate) fn bind_viewport_texture(&mut self, viewport_texture: std::sync::Arc) { + pub(crate) fn bind_viewport_texture(&mut self, viewport_texture: Texture) { self.viewport_texture = Some(viewport_texture); self.update_bindgroup(); } @@ -231,7 +231,7 @@ impl RenderState { let result = futures::executor::block_on(self.executor.render_vello_scene(&scene, size, &Default::default(), None)); match result { Ok(texture) => { - self.overlays_texture = Some(texture.into()); + self.overlays_texture = Some(texture); } Err(e) => { self.overlays_texture = None; diff --git a/desktop/wrapper/src/lib.rs b/desktop/wrapper/src/lib.rs index 5f2adff705..ebe6458c35 100644 --- a/desktop/wrapper/src/lib.rs +++ b/desktop/wrapper/src/lib.rs @@ -10,6 +10,7 @@ use std::sync::Arc; pub use graph_craft::application_io::resource::MmapResourceStorage; pub use graphite_editor::consts::{DOUBLE_CLICK_MILLISECONDS, FILE_EXTENSION}; +pub use wgpu_executor::Texture; pub use wgpu_executor::WgpuBackends; pub use wgpu_executor::WgpuContext; pub use wgpu_executor::WgpuContextBuilder; @@ -55,14 +56,14 @@ impl DesktopWrapper { pub async fn execute_node_graph() -> NodeGraphExecutionResult { let result = graphite_editor::node_graph_executor::run_node_graph().await; match result { - (true, texture) => NodeGraphExecutionResult::HasRun(texture.map(Into::into)), + (true, texture) => NodeGraphExecutionResult::HasRun(texture), (false, _) => NodeGraphExecutionResult::NotRun, } } } pub enum NodeGraphExecutionResult { - HasRun(Option>), + HasRun(Option), NotRun, } diff --git a/node-graph/libraries/raster-types/src/raster_types.rs b/node-graph/libraries/raster-types/src/raster_types.rs index 0f255d38bb..d210447182 100644 --- a/node-graph/libraries/raster-types/src/raster_types.rs +++ b/node-graph/libraries/raster-types/src/raster_types.rs @@ -140,7 +140,7 @@ mod cpu { pub use gpu::GPU; #[cfg(feature = "wgpu")] -pub use gpu::Texture; +pub use gpu::{Texture, TextureWeakRef}; #[cfg(feature = "wgpu")] mod gpu { @@ -149,37 +149,57 @@ mod gpu { use std::sync::Arc; #[derive(Clone, Debug, PartialEq, Eq, Hash, DynAny)] - pub struct Texture(Arc); + pub struct Texture(Arc); + + #[derive(Debug, PartialEq, Eq, Hash)] + struct TextureInner(wgpu::Texture); + + impl Drop for TextureInner { + fn drop(&mut self) { + self.0.destroy(); + } + } + + impl Texture { + pub fn is_shared(&self) -> bool { + Arc::strong_count(&self.0) > 1 + } + + pub fn is_weakly_shared(&self) -> bool { + Arc::weak_count(&self.0) > 0 + } + + pub fn downgrade(&self) -> TextureWeakRef { + TextureWeakRef(Arc::downgrade(&self.0)) + } + } + + #[derive(Clone, Debug)] + pub struct TextureWeakRef(std::sync::Weak); + + impl TextureWeakRef { + pub fn upgrade(&self) -> Option { + self.0.upgrade().map(Texture) + } + } impl Deref for Texture { type Target = wgpu::Texture; fn deref(&self) -> &Self::Target { - &self.0 + &self.0.0 } } impl AsRef for Texture { fn as_ref(&self) -> &wgpu::Texture { - &self.0 - } - } - - impl From> for Texture { - fn from(texture: Arc) -> Self { - Self(texture) + &self.0.0 } } impl From for Texture { fn from(texture: wgpu::Texture) -> Self { - Self(Arc::new(texture)) - } - } - - impl From for Arc { - fn from(texture: Texture) -> Self { - texture.0 + Self(Arc::new(TextureInner(texture))) } } diff --git a/node-graph/libraries/wgpu-executor/src/buffer.rs b/node-graph/libraries/wgpu-executor/src/buffer.rs new file mode 100644 index 0000000000..b6f58a323b --- /dev/null +++ b/node-graph/libraries/wgpu-executor/src/buffer.rs @@ -0,0 +1,34 @@ +use std::ops::Deref; +use std::sync::Arc; + +#[derive(Clone, Debug)] +pub struct Buffer(Arc); + +#[derive(Debug)] +struct BufferInner(wgpu::Buffer); + +impl Drop for BufferInner { + fn drop(&mut self) { + self.0.destroy(); + } +} + +impl Deref for Buffer { + type Target = wgpu::Buffer; + + fn deref(&self) -> &Self::Target { + &self.0.0 + } +} + +impl AsRef for Buffer { + fn as_ref(&self) -> &wgpu::Buffer { + &self.0.0 + } +} + +impl From for Buffer { + fn from(buffer: wgpu::Buffer) -> Self { + Self(Arc::new(BufferInner(buffer))) + } +} diff --git a/node-graph/libraries/wgpu-executor/src/lib.rs b/node-graph/libraries/wgpu-executor/src/lib.rs index 4c724ec684..e363f31c2e 100644 --- a/node-graph/libraries/wgpu-executor/src/lib.rs +++ b/node-graph/libraries/wgpu-executor/src/lib.rs @@ -1,3 +1,4 @@ +mod buffer; mod context; mod pipeline; pub mod shader_runtime; @@ -12,16 +13,18 @@ use core_types::color::SRGBA8; use futures::lock::Mutex; use glam::UVec2; use graphene_application_io::{ApplicationIo, EditorApi}; -use raster_types::Texture; use std::sync::Arc; use vello::{AaConfig, AaSupport, RenderParams, Renderer, RendererOptions, Scene}; +use wgpu::util::DeviceExt; use wgpu::{Origin3d, TextureAspect}; +pub use buffer::Buffer; pub use context::Context as WgpuContext; pub use context::ContextBuilder as WgpuContextBuilder; pub use pipeline::AsyncPipeline as AsyncWgpuPipeline; pub use pipeline::Pipeline as WgpuPipeline; pub use pipeline::PipelineCache as WgpuPipelineCache; +pub use raster_types::Texture; pub use rendering::RenderContext; pub use wgpu::Backends as WgpuBackends; pub use wgpu::Features as WgpuFeatures; @@ -30,7 +33,10 @@ pub use wgpu_sync::Instance as WgpuInstance; pub use wgpu_sync::Queue as WgpuQueue; pub use wgpu_sync::Surface as WgpuSurface; -const TEXTURE_CACHE_SIZE: u64 = 256 * 1024 * 1024; // 256 MiB +#[cfg(not(target_family = "wasm"))] +const TEXTURE_CACHE_SIZE: u64 = 1024 * 1024 * 1024; // 1GB +#[cfg(target_family = "wasm")] +const TEXTURE_CACHE_SIZE: u64 = 512 * 1024 * 1024; // 512MB #[derive(dyn_any::DynAny, Clone)] pub struct WgpuExecutor { @@ -41,16 +47,12 @@ impl WgpuExecutor { pub fn context(&self) -> &WgpuContext { &self.inner.context } - - pub fn shader_runtime(&self) -> &ShaderRuntime { - &self.inner.shader_runtime - } } #[derive(dyn_any::DynAny)] pub struct WgpuExecutorInner { context: WgpuContext, - texture_cache: Mutex, + texture_cache: std::sync::Mutex, vello_renderer: Mutex, shader_runtime: ShaderRuntime, } @@ -69,7 +71,7 @@ impl<'a, T: ApplicationIo> From<&'a EditorApi> for & impl WgpuExecutor { pub async fn render_vello_scene(&self, scene: &Scene, size: UVec2, context: &RenderContext, background: Option) -> Result { - let texture = self.request_texture(size).await; + let texture = self.request_texture(size); let texture_view = texture.create_view(&wgpu::TextureViewDescriptor::default()); @@ -109,8 +111,20 @@ impl WgpuExecutor { pipeline.init::

(self); } - pub async fn request_texture(&self, size: UVec2) -> Texture { - self.inner.texture_cache.lock().await.request_texture(&self.context().device, size) + pub fn request_texture(&self, size: UVec2) -> Texture { + self.request_texture_with_format(size, wgpu::TextureFormat::Rgba8Unorm) + } + + pub fn request_texture_with_format(&self, size: UVec2, format: wgpu::TextureFormat) -> Texture { + self.inner.texture_cache.lock().unwrap().request_texture(&self.context().device, size, format) + } + + pub fn create_buffer(&self, desc: &wgpu::BufferDescriptor) -> Buffer { + self.context().device.create_buffer(desc).into() + } + + pub fn create_buffer_init(&self, desc: &wgpu::util::BufferInitDescriptor) -> Buffer { + self.context().device.create_buffer_init(desc).into() } } @@ -134,7 +148,7 @@ impl WgpuExecutor { let texture_cache = TextureCache::new(TEXTURE_CACHE_SIZE); - let shader_runtime = ShaderRuntime::new(&context); + let shader_runtime = ShaderRuntime::default(); Some(Self { inner: Arc::new(WgpuExecutorInner { diff --git a/node-graph/libraries/wgpu-executor/src/shader_runtime/mod.rs b/node-graph/libraries/wgpu-executor/src/shader_runtime/mod.rs index a32e17aabb..540ddf8c8a 100644 --- a/node-graph/libraries/wgpu-executor/src/shader_runtime/mod.rs +++ b/node-graph/libraries/wgpu-executor/src/shader_runtime/mod.rs @@ -1,20 +1,10 @@ -use crate::WgpuContext; use crate::shader_runtime::per_pixel_adjust_runtime::PerPixelAdjustShaderRuntime; pub mod per_pixel_adjust_runtime; pub const FULLSCREEN_VERTEX_SHADER_NAME: &str = "fullscreen_vertex_fullscreen_vertex"; +#[derive(Default)] pub struct ShaderRuntime { - context: WgpuContext, per_pixel_adjust: PerPixelAdjustShaderRuntime, } - -impl ShaderRuntime { - pub fn new(context: &WgpuContext) -> Self { - Self { - context: context.clone(), - per_pixel_adjust: PerPixelAdjustShaderRuntime::new(), - } - } -} diff --git a/node-graph/libraries/wgpu-executor/src/shader_runtime/per_pixel_adjust_runtime.rs b/node-graph/libraries/wgpu-executor/src/shader_runtime/per_pixel_adjust_runtime.rs index 9f393d6945..761fbcad25 100644 --- a/node-graph/libraries/wgpu-executor/src/shader_runtime/per_pixel_adjust_runtime.rs +++ b/node-graph/libraries/wgpu-executor/src/shader_runtime/per_pixel_adjust_runtime.rs @@ -1,16 +1,17 @@ -use crate::WgpuContext; -use crate::shader_runtime::{FULLSCREEN_VERTEX_SHADER_NAME, ShaderRuntime}; +use crate::shader_runtime::FULLSCREEN_VERTEX_SHADER_NAME; +use crate::{Buffer, WgpuContext, WgpuExecutor}; use core_types::list::{Item, List}; use core_types::shaders::buffer_struct::BufferStruct; use futures::lock::Mutex; +use glam::UVec2; use raster_types::{GPU, Raster}; use std::borrow::Cow; use std::collections::HashMap; -use wgpu::util::{BufferInitDescriptor, DeviceExt}; +use wgpu::util::BufferInitDescriptor; use wgpu::{ - BindGroupDescriptor, BindGroupEntry, BindGroupLayoutDescriptor, BindGroupLayoutEntry, BindingResource, BindingType, Buffer, BufferBinding, BufferBindingType, BufferUsages, ColorTargetState, Face, + BindGroupDescriptor, BindGroupEntry, BindGroupLayoutDescriptor, BindGroupLayoutEntry, BindingResource, BindingType, BufferBinding, BufferBindingType, BufferUsages, ColorTargetState, Face, FragmentState, FrontFace, LoadOp, Operations, PipelineLayoutDescriptor, PolygonMode, PrimitiveState, PrimitiveTopology, RenderPassColorAttachment, RenderPassDescriptor, RenderPipelineDescriptor, - ShaderModuleDescriptor, ShaderSource, ShaderStages, StoreOp, TextureDescriptor, TextureDimension, TextureFormat, TextureSampleType, TextureViewDescriptor, TextureViewDimension, VertexState, + ShaderModuleDescriptor, ShaderSource, ShaderStages, StoreOp, TextureFormat, TextureSampleType, TextureViewDescriptor, TextureViewDimension, VertexState, }; pub struct PerPixelAdjustShaderRuntime { @@ -32,22 +33,21 @@ impl PerPixelAdjustShaderRuntime { } } -impl ShaderRuntime { +impl WgpuExecutor { pub async fn run_per_pixel_adjust(&self, shaders: &Shaders<'_>, textures: List>, args: Option<&T>) -> List> { - let mut cache = self.per_pixel_adjust.pipeline_cache.lock().await; + let mut cache = self.inner.shader_runtime.per_pixel_adjust.pipeline_cache.lock().await; let pipeline = cache .entry(shaders.fragment_shader_name.to_owned()) - .or_insert_with(|| PerPixelAdjustGraphicsPipeline::new(&self.context, shaders)); + .or_insert_with(|| PerPixelAdjustGraphicsPipeline::new(self.context(), shaders)); let arg_buffer = args.map(|args| { - let device = &self.context.device; - device.create_buffer_init(&BufferInitDescriptor { + self.create_buffer_init(&BufferInitDescriptor { label: Some(&format!("{} arg buffer", pipeline.name.as_str())), usage: BufferUsages::STORAGE, contents: bytemuck::bytes_of(&T::write(*args)), }) }); - pipeline.dispatch(&self.context, textures, arg_buffer) + pipeline.dispatch(self, textures, arg_buffer) } } @@ -160,9 +160,9 @@ impl PerPixelAdjustGraphicsPipeline { } } - pub fn dispatch(&self, context: &WgpuContext, textures: List>, arg_buffer: Option) -> List> { + pub fn dispatch(&self, executor: &WgpuExecutor, textures: List>, arg_buffer: Option) -> List> { assert_eq!(self.has_uniform, arg_buffer.is_some()); - let device = &context.device; + let device = &executor.context().device; let name = self.name.as_str(); let mut cmd = device.create_command_encoder(&wgpu::CommandEncoderDescriptor { @@ -203,16 +203,7 @@ impl PerPixelAdjustGraphicsPipeline { entries, }); - let tex_out = device.create_texture(&TextureDescriptor { - label: Some(&format!("{name} texture out")), - size: tex_in.size(), - mip_level_count: 1, - sample_count: 1, - dimension: TextureDimension::D2, - format, - usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_DST | wgpu::TextureUsages::COPY_SRC | wgpu::TextureUsages::RENDER_ATTACHMENT, - view_formats: &[format], - }); + let tex_out = executor.request_texture_with_format(UVec2::new(tex_in.width(), tex_in.height()), format); let view_out = tex_out.create_view(&TextureViewDescriptor::default()); let mut rp = cmd.begin_render_pass(&RenderPassDescriptor { @@ -237,7 +228,7 @@ impl PerPixelAdjustGraphicsPipeline { Item::from_parts(Raster::new_gpu(tex_out), attributes) }) .collect::>(); - context.queue.submit([cmd.finish()]); + executor.context().queue.submit([cmd.finish()]); out } } diff --git a/node-graph/libraries/wgpu-executor/src/texture_cache.rs b/node-graph/libraries/wgpu-executor/src/texture_cache.rs index aba3784f78..4b8c85671b 100644 --- a/node-graph/libraries/wgpu-executor/src/texture_cache.rs +++ b/node-graph/libraries/wgpu-executor/src/texture_cache.rs @@ -1,11 +1,10 @@ use glam::UVec2; use raster_types::Texture; use std::collections::VecDeque; -use std::sync::Arc; pub(crate) struct TextureCache { /// Always sorted oldest-first by insertion/last-use order. - textures: VecDeque>, + textures: VecDeque, max_free_bytes: u64, } @@ -17,49 +16,53 @@ impl TextureCache { } } - pub fn request_texture(&mut self, device: &wgpu::Device, size: UVec2) -> Texture { + pub fn request_texture(&mut self, device: &wgpu::Device, size: UVec2, format: wgpu::TextureFormat) -> Texture { let size = size.max(UVec2::ONE); if let Some(pos) = self .textures .iter() - .position(|texture| UVec2::new(texture.width(), texture.height()) == size && Arc::strong_count(texture) == 1) + .position(|texture| UVec2::new(texture.width(), texture.height()) == size && texture.format() == format && !texture.is_shared() && !texture.is_weakly_shared()) { let entry = self.textures.remove(pos).unwrap(); let texture = entry.clone(); self.textures.push_back(entry); - return texture.into(); + return texture; } - let incoming_bytes = size.x as u64 * size.y as u64 * 4; + let incoming_bytes = size.x as u64 * size.y as u64 * format.block_copy_size(None).unwrap_or(4) as u64; self.evict_until_fits(incoming_bytes); - let texture = Arc::new(device.create_texture(&wgpu::TextureDescriptor { - label: Some(&format!("cached_texture_{}x{}", size.x, size.y)), - size: wgpu::Extent3d { - width: size.x, - height: size.y, - depth_or_array_layers: 1, - }, - mip_level_count: 1, - sample_count: 1, - dimension: wgpu::TextureDimension::D2, - format: wgpu::TextureFormat::Rgba8Unorm, - usage: wgpu::TextureUsages::COPY_SRC | wgpu::TextureUsages::COPY_DST | wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::STORAGE_BINDING | wgpu::TextureUsages::RENDER_ATTACHMENT, - view_formats: &[], - })); + let texture: Texture = device + .create_texture(&wgpu::TextureDescriptor { + label: Some(&format!("cached_{}x{}", size.x, size.y)), + size: wgpu::Extent3d { + width: size.x, + height: size.y, + depth_or_array_layers: 1, + }, + mip_level_count: 1, + sample_count: 1, + dimension: wgpu::TextureDimension::D2, + format, + usage: { + let common = wgpu::TextureUsages::COPY_SRC | wgpu::TextureUsages::COPY_DST | wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::RENDER_ATTACHMENT; + match format { + wgpu::TextureFormat::Rgba8Unorm => common | wgpu::TextureUsages::STORAGE_BINDING, + _ => common, + } + }, + view_formats: &[], + }) + .into(); self.textures.push_back(texture.clone()); - texture.into() + texture } fn total_free_bytes(&self) -> u64 { - self.textures - .iter() - .filter(|texture| Arc::strong_count(texture) == 1) - .map(|texture| texture.memory_size_estimate()) - .sum() + self.textures.iter().filter(|texture| !texture.is_shared()).map(|texture| texture.memory_size_estimate()).sum() } fn evict_until_fits(&mut self, incoming_bytes: u64) { @@ -70,18 +73,19 @@ impl TextureCache { return; } - self.textures.retain(|texture| { - if free_bytes + incoming_bytes <= max_free_bytes { - return true; - } - if Arc::strong_count(texture) == 1 { - free_bytes -= texture.memory_size_estimate(); - texture.destroy(); - false - } else { - true - } - }); + for parked in [false, true] { + self.textures.retain(|texture| { + if free_bytes + incoming_bytes <= max_free_bytes { + return true; + } + if !texture.is_shared() && texture.is_weakly_shared() == parked { + free_bytes -= texture.memory_size_estimate(); + false + } else { + true + } + }); + } } } @@ -91,6 +95,6 @@ trait TextureMemoryCostEstimateExt { impl TextureMemoryCostEstimateExt for wgpu::Texture { fn memory_size_estimate(&self) -> u64 { - self.width() as u64 * self.height() as u64 * 4 + self.width() as u64 * self.height() as u64 * self.format().block_copy_size(None).unwrap_or(4) as u64 } } diff --git a/node-graph/libraries/wgpu-executor/src/texture_conversion.rs b/node-graph/libraries/wgpu-executor/src/texture_conversion.rs index f009a06d3c..1411a57f6b 100644 --- a/node-graph/libraries/wgpu-executor/src/texture_conversion.rs +++ b/node-graph/libraries/wgpu-executor/src/texture_conversion.rs @@ -1,40 +1,33 @@ -use crate::WgpuExecutor; +use crate::{Buffer, WgpuExecutor}; use core_types::Color; use core_types::color::SRGBA8; use core_types::list::{Item, List}; use core_types::ops::Convert; use core_types::transform::Footprint; use raster_types::Image; -use raster_types::{CPU, GPU, Raster}; -use wgpu::util::{DeviceExt, TextureDataOrder}; -use wgpu::{Extent3d, TextureDescriptor, TextureDimension, TextureFormat, TextureUsages}; +use raster_types::{CPU, GPU, Raster, Texture}; +use wgpu::{Extent3d, TextureFormat}; /// Uploads CPU image data to a GPU texture -/// -/// Creates a new WGPU texture with RGBA8UnormSrgb format and uploads the provided -/// image data. The texture is configured for binding, copying, and source operations. -fn upload_to_texture(device: &wgpu::Device, queue: &wgpu::Queue, image: &Raster) -> wgpu::Texture { +fn upload_to_texture(executor: &WgpuExecutor, queue: &wgpu::Queue, image: &Raster) -> Texture { let rgba8_data: Vec = image.data.iter().map(|x| (*x).into()).collect(); - device.create_texture_with_data( - queue, - &TextureDescriptor { - label: Some("upload_to_texture staging texture"), - size: Extent3d { - width: image.width, - height: image.height, - depth_or_array_layers: 1, - }, - mip_level_count: 1, - sample_count: 1, - dimension: TextureDimension::D2, - format: TextureFormat::Rgba8UnormSrgb, - usage: TextureUsages::TEXTURE_BINDING | TextureUsages::COPY_DST | TextureUsages::COPY_SRC, - view_formats: &[], - }, - TextureDataOrder::LayerMajor, + let texture = executor.request_texture_with_format(glam::UVec2::new(image.width, image.height), TextureFormat::Rgba8UnormSrgb); + queue.write_texture( + texture.as_image_copy(), bytemuck::cast_slice(rgba8_data.as_slice()), - ) + wgpu::TexelCopyBufferLayout { + offset: 0, + bytes_per_row: Some(4 * image.width), + rows_per_image: Some(image.height), + }, + Extent3d { + width: image.width, + height: image.height, + depth_or_array_layers: 1, + }, + ); + texture } /// Converts a Raster texture to Raster by downloading the underlying texture data. @@ -44,7 +37,7 @@ fn upload_to_texture(device: &wgpu::Device, queue: &wgpu::Queue, image: &Raster< /// - 4 bytes-per-pixel RGBA8 /// - Texture has COPY_SRC usage struct RasterGpuToRasterCpuConverter { - buffer: wgpu::Buffer, + buffer: Buffer, width: u32, height: u32, unpadded_bytes_per_row: u32, @@ -52,7 +45,7 @@ struct RasterGpuToRasterCpuConverter { _source: raster_types::Texture, } impl RasterGpuToRasterCpuConverter { - fn new(device: &wgpu::Device, encoder: &mut wgpu::CommandEncoder, data_gpu: Raster) -> Self { + fn new(executor: &WgpuExecutor, encoder: &mut wgpu::CommandEncoder, data_gpu: Raster) -> Self { let texture = data_gpu.data(); let width = texture.width(); let height = texture.height(); @@ -62,7 +55,7 @@ impl RasterGpuToRasterCpuConverter { let padded_bytes_per_row = unpadded_bytes_per_row.div_ceil(align) * align; let buffer_size = padded_bytes_per_row as u64 * height as u64; - let buffer = device.create_buffer(&wgpu::BufferDescriptor { + let buffer = executor.create_buffer(&wgpu::BufferDescriptor { label: Some("texture_download_buffer"), size: buffer_size, usage: wgpu::BufferUsages::COPY_DST | wgpu::BufferUsages::MAP_READ, @@ -151,13 +144,12 @@ impl<'i> Convert>, &'i WgpuExecutor> for List> { /// Converts a `List>` to `List>` by uploading each image to a texture impl<'i> Convert>, &'i WgpuExecutor> for List> { async fn convert(self, _: Footprint, executor: &'i WgpuExecutor) -> List> { - let device = &executor.context().device; let queue = executor.context().queue.lock(); let list = self .into_iter() .map(|row| { let (image, attributes) = row.into_parts(); - let texture = upload_to_texture(device, &queue, &image); + let texture = upload_to_texture(executor, &queue, &image); Item::from_parts(Raster::new_gpu(texture), attributes) }) @@ -171,9 +163,8 @@ impl<'i> Convert>, &'i WgpuExecutor> for List> { /// Converts single CPU raster to GPU by uploading to texture impl<'i> Convert, &'i WgpuExecutor> for Raster { async fn convert(self, _: Footprint, executor: &'i WgpuExecutor) -> Raster { - let device = &executor.context().device; let queue = executor.context().queue.lock(); - let texture = upload_to_texture(device, &queue, &self); + let texture = upload_to_texture(executor, &queue, &self); queue.submit([]); Raster::new_gpu(texture) @@ -202,7 +193,7 @@ impl<'i> Convert>, &'i WgpuExecutor> for List> { for row in self { let (element, attributes) = row.into_parts(); - converters.push(RasterGpuToRasterCpuConverter::new(device, &mut encoder, element)); + converters.push(RasterGpuToRasterCpuConverter::new(executor, &mut encoder, element)); rows_meta.push(Item::from_parts((), attributes)); } @@ -239,7 +230,7 @@ impl<'i> Convert, &'i WgpuExecutor> for Raster { label: Some("single_texture_download_encoder"), }); - let converter = RasterGpuToRasterCpuConverter::new(device, &mut encoder, self); + let converter = RasterGpuToRasterCpuConverter::new(executor, &mut encoder, self); queue.submit([encoder.finish()]); diff --git a/node-graph/node-macro/src/shader_nodes/per_pixel_adjust.rs b/node-graph/node-macro/src/shader_nodes/per_pixel_adjust.rs index e689817aea..2d9adbac6a 100644 --- a/node-graph/node-macro/src/shader_nodes/per_pixel_adjust.rs +++ b/node-graph/node-macro/src/shader_nodes/per_pixel_adjust.rs @@ -294,7 +294,7 @@ impl PerPixelAdjustCodegen<'_> { let entry_point_name = &self.entry_point_name; let body = quote! { { - #executor.into_element().shader_runtime().run_per_pixel_adjust(&::wgpu_executor::shader_runtime::per_pixel_adjust_runtime::Shaders { + #executor.into_element().run_per_pixel_adjust(&::wgpu_executor::shader_runtime::per_pixel_adjust_runtime::Shaders { wgsl_shader: crate::WGSL_SHADER, fragment_shader_name: super::#entry_point_name, has_uniform: #has_uniform, diff --git a/node-graph/nodes/gstd/src/render_background.rs b/node-graph/nodes/gstd/src/render_background.rs index dd2c0f3646..45abc4429e 100644 --- a/node-graph/nodes/gstd/src/render_background.rs +++ b/node-graph/nodes/gstd/src/render_background.rs @@ -9,8 +9,7 @@ use graph_craft::document::value::{RenderOutput, RenderOutputType}; use graphic_types::raster_types::Texture; use rendering::{RenderParams, SvgRender, SvgRenderOutput}; use std::fmt::Write; -use wgpu::util::DeviceExt; -use wgpu_executor::{AsyncWgpuPipeline, WgpuExecutor, WgpuPipelineCache}; +use wgpu_executor::{AsyncWgpuPipeline, Buffer, WgpuExecutor, WgpuPipelineCache}; #[node_macro::node(category(""))] async fn render_background<'a: 'n>( @@ -342,7 +341,7 @@ impl AsyncWgpuPipeline for CompositeBackground { } = args; let foreground_size = foreground.size(); - let output = executor.request_texture(UVec2::new(foreground_size.width, foreground_size.height)).await; + let output = executor.request_texture(UVec2::new(foreground_size.width, foreground_size.height)); if zoom <= 0. { return output; @@ -360,10 +359,8 @@ impl AsyncWgpuPipeline for CompositeBackground { let foreground_view = foreground.create_view(&wgpu::TextureViewDescriptor::default()); let checker_draws = if backgrounds.is_empty() { - vec![( - 3, - self.create_checker_bind_group(device, CompositeUniforms::fullscreen(viewport_size, screen_to_document, checker_size_doc)), - )] + let uniforms = CompositeUniforms::fullscreen(viewport_size, screen_to_document, checker_size_doc).create_buffer(executor); + vec![(3, self.create_checker_bind_group(device, &uniforms), uniforms)] } else { backgrounds .iter() @@ -378,8 +375,8 @@ impl AsyncWgpuPipeline for CompositeBackground { return None; } - let uniforms = CompositeUniforms::rect(min, max, document_to_screen, viewport_size, checker_size_doc); - Some((6, self.create_checker_bind_group(device, uniforms))) + let uniforms = CompositeUniforms::rect(min, max, document_to_screen, viewport_size, checker_size_doc).create_buffer(executor); + Some((6, self.create_checker_bind_group(device, &uniforms), uniforms)) }) .collect() }; @@ -421,13 +418,13 @@ impl AsyncWgpuPipeline for CompositeBackground { if backgrounds.is_empty() { pass.set_pipeline(&self.checker_viewport_pipeline); - for (vertex_count, bind_group) in &checker_draws { + for (vertex_count, bind_group, _uniforms) in &checker_draws { pass.set_bind_group(0, bind_group, &[]); pass.draw(0..*vertex_count, 0..1); } } else { pass.set_pipeline(&self.checker_rect_pipeline); - for (vertex_count, bind_group) in &checker_draws { + for (vertex_count, bind_group, _uniforms) in &checker_draws { pass.set_bind_group(0, bind_group, &[]); pass.draw(0..*vertex_count, 0..1); } @@ -445,19 +442,13 @@ impl AsyncWgpuPipeline for CompositeBackground { } impl CompositeBackground { - fn create_checker_bind_group(&self, device: &wgpu::Device, uniforms: CompositeUniforms) -> wgpu::BindGroup { - let buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor { - label: Some("background_checker_uniforms"), - contents: bytemuck::bytes_of(&uniforms), - usage: wgpu::BufferUsages::UNIFORM, - }); - + fn create_checker_bind_group(&self, device: &wgpu::Device, uniforms: &Buffer) -> wgpu::BindGroup { device.create_bind_group(&wgpu::BindGroupDescriptor { label: Some("background_checker_bind_group"), layout: &self.checker_bind_group_layout, entries: &[wgpu::BindGroupEntry { binding: 0, - resource: buffer.as_entire_binding(), + resource: uniforms.as_entire_binding(), }], }) } @@ -499,4 +490,12 @@ impl CompositeUniforms { _pad: 0., } } + + fn create_buffer(&self, executor: &WgpuExecutor) -> Buffer { + executor.create_buffer_init(&wgpu::util::BufferInitDescriptor { + label: Some("background_checker_uniforms"), + contents: bytemuck::bytes_of(self), + usage: wgpu::BufferUsages::UNIFORM, + }) + } } diff --git a/node-graph/nodes/gstd/src/render_cache.rs b/node-graph/nodes/gstd/src/render_cache.rs index ae5a9cbb96..e2a92f0ff2 100644 --- a/node-graph/nodes/gstd/src/render_cache.rs +++ b/node-graph/nodes/gstd/src/render_cache.rs @@ -391,7 +391,7 @@ pub async fn render_output_cache<'a: 'n>( } let executor = executor.into_element().expect("GPU executor not available"); - let output_texture = executor.request_texture(physical_resolution).await; + let output_texture = executor.request_texture(physical_resolution); let combined_metadata = composite_cached_regions(&all_regions, &output_texture, &device_origin_offset, &footprint.transform, executor); diff --git a/node-graph/nodes/gstd/src/render_pixel_preview.rs b/node-graph/nodes/gstd/src/render_pixel_preview.rs index a41ea7daf0..eb1546b022 100644 --- a/node-graph/nodes/gstd/src/render_pixel_preview.rs +++ b/node-graph/nodes/gstd/src/render_pixel_preview.rs @@ -177,7 +177,7 @@ impl AsyncWgpuPipeline for PixelPreview { let context = &executor.context(); let &PixelPreviewArgs { source, transform, size } = args; - let output = executor.request_texture(size).await; + let output = executor.request_texture(size); let source_view = source.create_view(&wgpu::TextureViewDescriptor::default()); let output_view = output.create_view(&wgpu::TextureViewDescriptor::default());