diff --git a/Cargo.toml b/Cargo.toml index 660fa93..c2419ed 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,3 +27,6 @@ bytemuck = { version = "1.12.1", features = ["derive"] } smallvec = "1.8.0" moscato = { git = "https://github.com/dfrg/pinot" } peniko = { git = "https://github.com/linebender/peniko" } + +[features] +buffer_labels = [] diff --git a/examples/with_winit/Cargo.toml b/examples/with_winit/Cargo.toml index aeb7cd5..fd7b9b6 100644 --- a/examples/with_winit/Cargo.toml +++ b/examples/with_winit/Cargo.toml @@ -9,7 +9,7 @@ publish = false [dependencies] wgpu = "0.14" -vello = { path = "../../" } +vello = { path = "../../", features = ["buffer_labels"] } winit = "0.27.5" pollster = "0.2.5" # for picosvg diff --git a/src/engine.rs b/src/engine.rs index 0c4963f..2039d9d 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -58,6 +58,7 @@ pub struct Recording { pub struct BufProxy { size: u64, id: Id, + name: &'static str, } #[derive(Copy, Clone, PartialEq, Eq)] @@ -118,15 +119,29 @@ pub enum BindType { // TODO: Uniform, Sampler, maybe others } +struct BindMapBuffer { + buffer: Buffer, + #[cfg_attr(not(feature = "buffer_labels"), allow(unused))] + label: &'static str, +} + #[derive(Default)] struct BindMap { - buf_map: HashMap, + buf_map: HashMap, image_map: HashMap, } +#[derive(Hash, PartialEq, Eq)] +struct BufferProperties { + size: u64, + usages: BufferUsages, + #[cfg(feature = "buffer_labels")] + name: &'static str, +} + #[derive(Default)] struct ResourcePool { - bufs: HashMap<(u64, BufferUsages), Vec>, + bufs: HashMap>, } impl Engine { @@ -147,11 +162,12 @@ impl Engine { pub fn add_shader( &mut self, device: &Device, + label: &'static str, wgsl: Cow<'static, str>, layout: &[BindType], ) -> Result { let shader_module = device.create_shader_module(wgpu::ShaderModuleDescriptor { - label: None, + label: Some(label), source: wgpu::ShaderSource::Wgsl(wgsl), }); let entries = layout @@ -213,7 +229,7 @@ impl Engine { push_constant_ranges: &[], }); let pipeline = device.create_compute_pipeline(&wgpu::ComputePipelineDescriptor { - label: None, + label: Some(label), layout: Some(&compute_pipeline_layout), module: &shader_module, entry_point: "main", @@ -243,18 +259,18 @@ impl Engine { Command::Upload(buf_proxy, bytes) => { let usage = BufferUsages::COPY_SRC | BufferUsages::COPY_DST | BufferUsages::STORAGE; - let buf = self.pool.get_buf(bytes.len() as u64, usage, device); + let buf = self.pool.get_buf(buf_proxy, usage, device); // TODO: if buffer is newly created, might be better to make it mapped at creation // and copy. However, we expect reuse will be most common. queue.write_buffer(&buf, 0, bytes); - bind_map.insert_buf(buf_proxy.id, buf); + bind_map.insert_buf(buf_proxy, buf); } Command::UploadUniform(buf_proxy, bytes) => { let usage = BufferUsages::UNIFORM | BufferUsages::COPY_DST; // Same consideration as above - let buf = self.pool.get_buf(bytes.len() as u64, usage, device); + let buf = self.pool.get_buf(buf_proxy, usage, device); queue.write_buffer(&buf, 0, bytes); - bind_map.insert_buf(buf_proxy.id, buf); + bind_map.insert_buf(buf_proxy, buf); } Command::UploadImage(image_proxy, bytes) => { let buf = device.create_buffer_init(&wgpu::util::BufferInitDescriptor { @@ -326,12 +342,12 @@ impl Engine { Command::Download(proxy) => { let src_buf = bind_map.buf_map.get(&proxy.id).ok_or("buffer not in map")?; let buf = device.create_buffer(&wgpu::BufferDescriptor { - label: None, + label: Some(proxy.name), size: proxy.size, usage: wgpu::BufferUsages::MAP_READ | wgpu::BufferUsages::COPY_DST, mapped_at_creation: false, }); - encoder.copy_buffer_to_buffer(src_buf, 0, &buf, 0, proxy.size); + encoder.copy_buffer_to_buffer(&src_buf.buffer, 0, &buf, 0, proxy.size); downloads.buf_map.insert(proxy.id, buf); } Command::Clear(proxy, offset, size) => { @@ -351,16 +367,16 @@ impl Recording { self.commands.push(cmd); } - pub fn upload(&mut self, data: impl Into>) -> BufProxy { + pub fn upload(&mut self, name: &'static str, data: impl Into>) -> BufProxy { let data = data.into(); - let buf_proxy = BufProxy::new(data.len() as u64); + let buf_proxy = BufProxy::new(data.len() as u64, name); self.push(Command::Upload(buf_proxy, data)); buf_proxy } - pub fn upload_uniform(&mut self, data: impl Into>) -> BufProxy { + pub fn upload_uniform(&mut self, name: &'static str, data: impl Into>) -> BufProxy { let data = data.into(); - let buf_proxy = BufProxy::new(data.len() as u64); + let buf_proxy = BufProxy::new(data.len() as u64, name); self.push(Command::UploadUniform(buf_proxy, data)); buf_proxy } @@ -400,11 +416,12 @@ impl Recording { } impl BufProxy { - pub fn new(size: u64) -> Self { + pub fn new(size: u64, name: &'static str) -> Self { let id = Id::next(); BufProxy { id, size: size.max(16), + name, } } } @@ -431,8 +448,8 @@ impl ImageProxy { } impl ResourceProxy { - pub fn new_buf(size: u64) -> Self { - Self::Buf(BufProxy::new(size)) + pub fn new_buf(size: u64, name: &'static str) -> Self { + Self::Buf(BufProxy::new(size, name)) } pub fn new_image(width: u32, height: u32, format: ImageFormat) -> Self { @@ -475,8 +492,14 @@ impl Id { } impl BindMap { - fn insert_buf(&mut self, id: Id, buf: Buffer) { - self.buf_map.insert(id, buf); + fn insert_buf(&mut self, proxy: &BufProxy, buffer: Buffer) { + self.buf_map.insert( + proxy.id, + BindMapBuffer { + buffer, + label: proxy.name, + }, + ); } fn insert_image(&mut self, id: Id, image: Texture, image_view: TextureView) { @@ -530,8 +553,11 @@ impl BindMap { if let Entry::Vacant(v) = self.buf_map.entry(proxy.id) { let usage = BufferUsages::COPY_SRC | BufferUsages::COPY_DST | BufferUsages::STORAGE; - let buf = pool.get_buf(proxy.size, usage, device); - v.insert(buf); + let buf = pool.get_buf(&proxy, usage, device); + v.insert(BindMapBuffer { + buffer: buf, + label: proxy.name, + }); } } ResourceProxy::Image(proxy) => { @@ -573,7 +599,7 @@ impl BindMap { .map(|(i, proxy)| match proxy { ResourceProxy::Buf(proxy) => { let buf = find_buf(external_resources, proxy) - .or_else(|| self.buf_map.get(&proxy.id)) + .or_else(|| self.buf_map.get(&proxy.id).map(|buf| &buf.buffer)) .unwrap(); Ok(wgpu::BindGroupEntry { binding: i as u32, @@ -606,11 +632,16 @@ impl BindMap { pool: &mut ResourcePool, ) -> Result<&Buffer, Error> { match self.buf_map.entry(proxy.id) { - Entry::Occupied(occupied) => Ok(occupied.into_mut()), + Entry::Occupied(occupied) => Ok(&occupied.into_mut().buffer), Entry::Vacant(vacant) => { let usage = BufferUsages::COPY_SRC | BufferUsages::COPY_DST | BufferUsages::STORAGE; - let buf = pool.get_buf(proxy.size, usage, device); - Ok(vacant.insert(buf)) + let buf = pool.get_buf(&proxy, usage, device); + Ok(&vacant + .insert(BindMapBuffer { + buffer: buf, + label: proxy.name, + }) + .buffer) } } } @@ -656,14 +687,23 @@ const SIZE_CLASS_BITS: u32 = 1; impl ResourcePool { /// Get a buffer from the pool or create one. - fn get_buf(&mut self, size: u64, usage: BufferUsages, device: &Device) -> Buffer { - let rounded_size = Self::size_class(size, SIZE_CLASS_BITS); - if let Some(buf_vec) = self.bufs.get_mut(&(rounded_size, usage)) { + fn get_buf(&mut self, proxy: &BufProxy, usage: BufferUsages, device: &Device) -> Buffer { + let rounded_size = Self::size_class(proxy.size, SIZE_CLASS_BITS); + let props = BufferProperties { + size: rounded_size, + usages: usage, + #[cfg(feature = "buffer_labels")] + name: proxy.name, + }; + if let Some(buf_vec) = self.bufs.get_mut(&props) { if let Some(buf) = buf_vec.pop() { return buf; } } device.create_buffer(&wgpu::BufferDescriptor { + #[cfg(feature = "buffer_labels")] + label: Some(proxy.name), + #[cfg(not(feature = "buffer_labels"))] label: None, size: rounded_size, usage, @@ -673,9 +713,14 @@ impl ResourcePool { fn reap_bindmap(&mut self, bind_map: BindMap) { for (_id, buf) in bind_map.buf_map { - let size = buf.size(); - let usage = buf.usage(); - self.bufs.entry((size, usage)).or_default().push(buf); + let size = buf.buffer.size(); + let props = BufferProperties { + size, + usages: buf.buffer.usage(), + #[cfg(feature = "buffer_labels")] + name: buf.label, + }; + self.bufs.entry(props).or_default().push(buf.buffer); } } diff --git a/src/render.rs b/src/render.rs index ab08a0c..5d4000c 100644 --- a/src/render.rs +++ b/src/render.rs @@ -77,10 +77,10 @@ fn render(scene: &Scene, shaders: &Shaders) -> (Recording, BufProxy) { pathdata_base, ..Default::default() }; - let scene_buf = recording.upload(scene); - let config_buf = recording.upload_uniform(bytemuck::bytes_of(&config)); + let scene_buf = recording.upload("scene", scene); + let config_buf = recording.upload_uniform("config", bytemuck::bytes_of(&config)); - let reduced_buf = BufProxy::new(pathtag_wgs as u64 * TAG_MONOID_SIZE); + let reduced_buf = BufProxy::new(pathtag_wgs as u64 * TAG_MONOID_SIZE, "reduced_buf"); // TODO: really only need pathtag_wgs - 1 recording.dispatch( shaders.pathtag_reduce, @@ -88,8 +88,10 @@ fn render(scene: &Scene, shaders: &Shaders) -> (Recording, BufProxy) { [config_buf, scene_buf, reduced_buf], ); - let tagmonoid_buf = - BufProxy::new(pathtag_wgs as u64 * shaders::PATHTAG_REDUCE_WG as u64 * TAG_MONOID_SIZE); + let tagmonoid_buf = BufProxy::new( + pathtag_wgs as u64 * shaders::PATHTAG_REDUCE_WG as u64 * TAG_MONOID_SIZE, + "tagmonoid_buf", + ); recording.dispatch( shaders.pathtag_scan, (pathtag_wgs as u32, 1, 1), @@ -99,8 +101,8 @@ fn render(scene: &Scene, shaders: &Shaders) -> (Recording, BufProxy) { let path_coarse_wgs = (n_pathtag as u32 + shaders::PATH_COARSE_WG - 1) / shaders::PATH_COARSE_WG; // TODO: more principled size calc - let tiles_buf = BufProxy::new(4097 * 8); - let segments_buf = BufProxy::new(256 * 24); + let tiles_buf = BufProxy::new(4097 * 8, "tiles_buf"); + let segments_buf = BufProxy::new(256 * 24, "segments_buf"); recording.clear_all(tiles_buf); recording.dispatch( shaders.path_coarse, @@ -119,7 +121,7 @@ fn render(scene: &Scene, shaders: &Shaders) -> (Recording, BufProxy) { [config_buf, tiles_buf], ); let out_buf_size = config.width_in_tiles * config.height_in_tiles * 256; - let out_buf = BufProxy::new(out_buf_size as u64); + let out_buf = BufProxy::new(out_buf_size as u64, "out_buf"); recording.dispatch( shaders.fine, (config.width_in_tiles, config.height_in_tiles, 1), @@ -180,8 +182,9 @@ pub fn render_encoding_full( layout: packed.layout, }; // println!("{:?}", config); - let scene_buf = ResourceProxy::Buf(recording.upload(packed.data)); - let config_buf = ResourceProxy::Buf(recording.upload_uniform(bytemuck::bytes_of(&config))); + let scene_buf = ResourceProxy::Buf(recording.upload("scene", packed.data)); + let config_buf = + ResourceProxy::Buf(recording.upload_uniform("config", bytemuck::bytes_of(&config))); let pathtag_wgs = pathtag_padded / (4 * shaders::PATHTAG_REDUCE_WG as usize); let pathtag_large = pathtag_wgs > shaders::PATHTAG_REDUCE_WG as usize; @@ -190,7 +193,8 @@ pub fn render_encoding_full( } else { pathtag_wgs }; - let reduced_buf = ResourceProxy::new_buf(reduced_size as u64 * TAG_MONOID_FULL_SIZE); + let reduced_buf = + ResourceProxy::new_buf(reduced_size as u64 * TAG_MONOID_FULL_SIZE, "reduced_buf"); // TODO: really only need pathtag_wgs - 1 recording.dispatch( shaders.pathtag_reduce, @@ -200,13 +204,17 @@ pub fn render_encoding_full( let mut pathtag_parent = reduced_buf; if pathtag_large { let reduced2_size = shaders::PATHTAG_REDUCE_WG as usize; - let reduced2_buf = ResourceProxy::new_buf(reduced2_size as u64 * TAG_MONOID_FULL_SIZE); + let reduced2_buf = + ResourceProxy::new_buf(reduced2_size as u64 * TAG_MONOID_FULL_SIZE, "reduced2_buf"); recording.dispatch( shaders.pathtag_reduce2, (reduced2_size as u32, 1, 1), [reduced_buf, reduced2_buf], ); - let reduced_scan_buf = ResourceProxy::new_buf(pathtag_wgs as u64 * TAG_MONOID_FULL_SIZE); + let reduced_scan_buf = ResourceProxy::new_buf( + pathtag_wgs as u64 * TAG_MONOID_FULL_SIZE, + "reduced_scan_buf", + ); recording.dispatch( shaders.pathtag_scan1, (reduced_size as u32 / shaders::PATHTAG_REDUCE_WG, 1, 1), @@ -217,6 +225,7 @@ pub fn render_encoding_full( let tagmonoid_buf = ResourceProxy::new_buf( pathtag_wgs as u64 * shaders::PATHTAG_REDUCE_WG as u64 * TAG_MONOID_FULL_SIZE, + "tagmonoid_buf", ); let pathtag_scan = if pathtag_large { shaders.pathtag_scan_large @@ -229,13 +238,13 @@ pub fn render_encoding_full( [config_buf, scene_buf, pathtag_parent, tagmonoid_buf], ); let drawobj_wgs = (n_drawobj + shaders::PATH_BBOX_WG - 1) / shaders::PATH_BBOX_WG; - let path_bbox_buf = ResourceProxy::new_buf(n_paths as u64 * PATH_BBOX_SIZE); + let path_bbox_buf = ResourceProxy::new_buf(n_paths as u64 * PATH_BBOX_SIZE, "path_bbox_buf"); recording.dispatch( shaders.bbox_clear, (drawobj_wgs, 1, 1), [config_buf, path_bbox_buf], ); - let cubic_buf = ResourceProxy::new_buf(n_pathtag as u64 * CUBIC_SIZE); + let cubic_buf = ResourceProxy::new_buf(n_pathtag as u64 * CUBIC_SIZE, "cubic_buf"); let path_coarse_wgs = (n_pathtag as u32 + shaders::PATH_COARSE_WG - 1) / shaders::PATH_COARSE_WG; recording.dispatch( @@ -249,15 +258,18 @@ pub fn render_encoding_full( cubic_buf, ], ); - let draw_reduced_buf = ResourceProxy::new_buf(drawobj_wgs as u64 * DRAWMONOID_SIZE); + let draw_reduced_buf = + ResourceProxy::new_buf(drawobj_wgs as u64 * DRAWMONOID_SIZE, "draw_reduced_buf"); recording.dispatch( shaders.draw_reduce, (drawobj_wgs, 1, 1), [config_buf, scene_buf, draw_reduced_buf], ); - let draw_monoid_buf = ResourceProxy::new_buf(n_drawobj as u64 * DRAWMONOID_SIZE); - let info_bin_data_buf = ResourceProxy::new_buf(1 << 20); - let clip_inp_buf = ResourceProxy::new_buf(encoding.n_clips as u64 * CLIP_INP_SIZE); + let draw_monoid_buf = + ResourceProxy::new_buf(n_drawobj as u64 * DRAWMONOID_SIZE, "draw_monoid_buf"); + let info_bin_data_buf = ResourceProxy::new_buf(1 << 20, "info_bin_data_buf"); + let clip_inp_buf = + ResourceProxy::new_buf(encoding.n_clips as u64 * CLIP_INP_SIZE, "clip_inp_buf"); recording.dispatch( shaders.draw_leaf, (drawobj_wgs, 1, 1), @@ -271,9 +283,11 @@ pub fn render_encoding_full( clip_inp_buf, ], ); - let clip_el_buf = ResourceProxy::new_buf(encoding.n_clips as u64 * CLIP_EL_SIZE); - let clip_bic_buf = - ResourceProxy::new_buf((n_clip / shaders::CLIP_REDUCE_WG) as u64 * CLIP_BIC_SIZE); + let clip_el_buf = ResourceProxy::new_buf(encoding.n_clips as u64 * CLIP_EL_SIZE, "clip_el_buf"); + let clip_bic_buf = ResourceProxy::new_buf( + (n_clip / shaders::CLIP_REDUCE_WG) as u64 * CLIP_BIC_SIZE, + "clip_bic_buf", + ); let clip_wg_reduce = n_clip.saturating_sub(1) / shaders::CLIP_REDUCE_WG; if clip_wg_reduce > 0 { recording.dispatch( @@ -289,7 +303,7 @@ pub fn render_encoding_full( ); } let clip_wg = (n_clip + shaders::CLIP_REDUCE_WG - 1) / shaders::CLIP_REDUCE_WG; - let clip_bbox_buf = ResourceProxy::new_buf(n_clip as u64 * CLIP_BBOX_SIZE); + let clip_bbox_buf = ResourceProxy::new_buf(n_clip as u64 * CLIP_BBOX_SIZE, "clip_bbox_buf"); if clip_wg > 0 { recording.dispatch( shaders.clip_leaf, @@ -305,11 +319,14 @@ pub fn render_encoding_full( ], ); } - let draw_bbox_buf = ResourceProxy::new_buf(n_paths as u64 * DRAW_BBOX_SIZE); - let bump_buf = BufProxy::new(BUMP_SIZE); + let draw_bbox_buf = ResourceProxy::new_buf(n_paths as u64 * DRAW_BBOX_SIZE, "draw_bbox_buf"); + let bump_buf = BufProxy::new(BUMP_SIZE, "bump_buf"); let width_in_bins = (config.width_in_tiles + 15) / 16; let height_in_bins = (config.height_in_tiles + 15) / 16; - let bin_header_buf = ResourceProxy::new_buf((256 * drawobj_wgs) as u64 * BIN_HEADER_SIZE); + let bin_header_buf = ResourceProxy::new_buf( + (256 * drawobj_wgs) as u64 * BIN_HEADER_SIZE, + "bin_header_buf", + ); recording.clear_all(bump_buf); let bump_buf = ResourceProxy::Buf(bump_buf); recording.dispatch( @@ -329,8 +346,8 @@ pub fn render_encoding_full( // Note: this only needs to be rounded up because of the workaround to store the tile_offset // in storage rather than workgroup memory. let n_path_aligned = align_up(n_paths as usize, 256); - let path_buf = ResourceProxy::new_buf(n_path_aligned as u64 * PATH_SIZE); - let tile_buf = ResourceProxy::new_buf(1 << 24); + let path_buf = ResourceProxy::new_buf(n_path_aligned as u64 * PATH_SIZE, "path_buf"); + let tile_buf = ResourceProxy::new_buf(1 << 24, "tile_buf"); let path_wgs = (n_paths + shaders::PATH_BBOX_WG - 1) / shaders::PATH_BBOX_WG; recording.dispatch( shaders.tile_alloc, @@ -345,7 +362,7 @@ pub fn render_encoding_full( ], ); - let segments_buf = ResourceProxy::new_buf(1 << 24); + let segments_buf = ResourceProxy::new_buf(1 << 24, "segments_buf"); recording.dispatch( shaders.path_coarse, (path_coarse_wgs, 1, 1), @@ -365,7 +382,7 @@ pub fn render_encoding_full( (path_wgs, 1, 1), [config_buf, path_buf, tile_buf], ); - let ptcl_buf = ResourceProxy::new_buf(1 << 24); + let ptcl_buf = ResourceProxy::new_buf(1 << 24, "ptcl_buf"); recording.dispatch( shaders.coarse, (width_in_bins, height_in_bins, 1), diff --git a/src/shaders.rs b/src/shaders.rs index a485cb4..6640938 100644 --- a/src/shaders.rs +++ b/src/shaders.rs @@ -73,11 +73,13 @@ pub fn init_shaders(device: &Device, engine: &mut Engine) -> Result Result Result Result Result Result Result Result Result Result Result Result Result Result Result