From 261d60e456b678939b8a0ceff4d8eafcd44e582e Mon Sep 17 00:00:00 2001 From: Samson <16504129+sagudev@users.noreply.github.com> Date: Fri, 13 Sep 2024 15:32:00 +0200 Subject: webgpu: Do one allocation less on presentation by keeping GPUBuffer mapped (#33387) * `GPUPresentationBuffer` in `WGPUExternalImages` Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com> * mv presentation_buffer in if let Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com> * docs Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com> --------- Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com> --- components/webgpu/swapchain.rs | 105 +++++++++++++++++++++++++++++------------ 1 file changed, 74 insertions(+), 31 deletions(-) (limited to 'components/webgpu') diff --git a/components/webgpu/swapchain.rs b/components/webgpu/swapchain.rs index 145155b4145..695d8d91b86 100644 --- a/components/webgpu/swapchain.rs +++ b/components/webgpu/swapchain.rs @@ -4,6 +4,7 @@ use std::collections::HashMap; use std::ops::ControlFlow; +use std::ptr::NonNull; use std::slice; use std::sync::{Arc, Mutex, MutexGuard}; @@ -39,6 +40,41 @@ impl MallocSizeOf for WebGPUContextId { pub type WGPUImageMap = Arc>>; +struct GPUPresentationBuffer { + global: Arc, + buffer_id: id::BufferId, + data: NonNull, + size: usize, +} + +// This is safe because `GPUPresentationBuffer` holds exclusive access to ptr +unsafe impl Send for GPUPresentationBuffer {} +unsafe impl Sync for GPUPresentationBuffer {} + +impl GPUPresentationBuffer { + fn new(global: Arc, buffer_id: id::BufferId, buffer_size: u64) -> Self { + let (data, size) = global + .buffer_get_mapped_range(buffer_id, 0, Some(buffer_size)) + .unwrap(); + GPUPresentationBuffer { + global, + buffer_id, + data, + size: size as usize, + } + } + + fn slice(&self) -> &[u8] { + unsafe { slice::from_raw_parts(self.data.as_ptr(), self.size) } + } +} + +impl Drop for GPUPresentationBuffer { + fn drop(&mut self) { + let _ = self.global.buffer_unmap(self.buffer_id); + } +} + #[derive(Default)] pub struct WGPUExternalImages { pub images: WGPUImageMap, @@ -52,7 +88,11 @@ impl WebrenderExternalImageApi for WGPUExternalImages { let data; if let Some(present_data) = self.images.lock().unwrap().get(&id) { size = present_data.image_desc.size.cast_unit(); - data = present_data.data.clone(); + data = if let Some(present_data) = &present_data.data { + present_data.slice().to_vec() + } else { + present_data.dummy_data() + }; } else { size = Size2D::new(0, 0); data = Vec::new(); @@ -71,15 +111,15 @@ impl WebrenderExternalImageApi for WGPUExternalImages { } pub struct PresentationData { - pub device_id: id::DeviceId, - pub queue_id: id::QueueId, - pub data: Vec, - pub unassigned_buffer_ids: ArrayVec, - pub available_buffer_ids: ArrayVec, - pub queued_buffer_ids: ArrayVec, - pub image_key: ImageKey, - pub image_desc: ImageDescriptor, - pub image_data: ImageData, + device_id: id::DeviceId, + queue_id: id::QueueId, + data: Option, + unassigned_buffer_ids: ArrayVec, + available_buffer_ids: ArrayVec, + queued_buffer_ids: ArrayVec, + image_key: ImageKey, + image_desc: ImageDescriptor, + image_data: ImageData, } impl PresentationData { @@ -91,18 +131,10 @@ impl PresentationData { image_desc: ImageDescriptor, image_data: ImageData, ) -> Self { - let height = image_desc.size.height; Self { device_id, queue_id, - // TODO: transparent black image - data: vec![ - 255; - (image_desc - .stride - .expect("Stride should be set when creating swapchain") * - height) as usize - ], + data: None, unassigned_buffer_ids: buffer_ids, available_buffer_ids: ArrayVec::::new(), queued_buffer_ids: ArrayVec::::new(), @@ -111,6 +143,23 @@ impl PresentationData { image_data, } } + + fn dummy_data(&self) -> Vec { + let size = (self + .image_desc + .stride + .expect("Stride should be set when creating swapchain") * + self.image_desc.size.height) as usize; + vec![0; size] + } + + fn unmap_old_buffer(&mut self, presentation_buffer: GPUPresentationBuffer) { + self.queued_buffer_ids + .retain(|b_id| *b_id != presentation_buffer.buffer_id); + self.available_buffer_ids + .push(presentation_buffer.buffer_id); + drop(presentation_buffer); + } } impl crate::WGPU { @@ -304,14 +353,10 @@ fn update_wr_image( ) { match result { Ok(()) => { - let (slice_pointer, range_size) = global - .buffer_get_mapped_range(buffer_id, 0, Some(buffer_size as u64)) - .unwrap(); - let data = - unsafe { slice::from_raw_parts(slice_pointer.as_ptr(), range_size as usize) } - .to_vec(); if let Some(present_data) = wgpu_image_map.lock().unwrap().get_mut(&context_id) { - present_data.data = data; + let presentation_buffer = + GPUPresentationBuffer::new(global, buffer_id, buffer_size); + let old_presentation_buffer = present_data.data.replace(presentation_buffer); let mut txn = Transaction::new(); txn.update_image( present_data.image_key, @@ -323,14 +368,12 @@ fn update_wr_image( .lock() .unwrap() .send_transaction(webrender_document, txn); - present_data - .queued_buffer_ids - .retain(|b_id| *b_id != buffer_id); - present_data.available_buffer_ids.push(buffer_id); + if let Some(old_presentation_buffer) = old_presentation_buffer { + present_data.unmap_old_buffer(old_presentation_buffer) + } } else { error!("Data not found for {:?}", context_id); } - let _ = global.buffer_unmap(buffer_id); }, _ => error!("Could not map buffer({:?})", buffer_id), } -- cgit v1.2.3