diff options
-rw-r--r-- | components/script/dom/gpubuffer.rs | 10 | ||||
-rw-r--r-- | components/webgpu/lib.rs | 259 |
2 files changed, 95 insertions, 174 deletions
diff --git a/components/script/dom/gpubuffer.rs b/components/script/dom/gpubuffer.rs index bfffb98bd73..e48768ea514 100644 --- a/components/script/dom/gpubuffer.rs +++ b/components/script/dom/gpubuffer.rs @@ -382,15 +382,5 @@ impl AsyncWGPUListener for GPUBuffer { None => unreachable!("Failed to get a response for BufferMapAsync"), } *self.map_promise.borrow_mut() = None; - if let Err(e) = self - .channel - .0 - .send((None, WebGPURequest::BufferMapComplete(self.buffer.0))) - { - warn!( - "Failed to send BufferMapComplete({:?}) ({})", - self.buffer.0, e - ); - } } } diff --git a/components/webgpu/lib.rs b/components/webgpu/lib.rs index 7cebc6739ea..d92b89b79ce 100644 --- a/components/webgpu/lib.rs +++ b/components/webgpu/lib.rs @@ -13,7 +13,6 @@ use std::borrow::Cow; use std::cell::RefCell; use std::collections::HashMap; use std::num::NonZeroU64; -use std::rc::Rc; use std::slice; use std::sync::{Arc, Mutex}; use std::time::{Duration, Instant}; @@ -45,13 +44,13 @@ use wgpu::id; use wgpu::instance::RequestAdapterOptions; use wgpu::pipeline::{ComputePipelineDescriptor, RenderPipelineDescriptor, ShaderModuleDescriptor}; use wgpu::resource::{ - BufferDescriptor, BufferMapAsyncStatus, BufferMapCallback, BufferMapCallbackC, - BufferMapOperation, SamplerDescriptor, TextureDescriptor, TextureViewDescriptor, + BufferDescriptor, BufferMapCallback, BufferMapOperation, SamplerDescriptor, TextureDescriptor, + TextureViewDescriptor, }; use wgt::InstanceDescriptor; pub type ErrorScopeId = NonZeroU64; -const DEVICE_POLL_INTERVAL: u64 = 100; +const DEVICE_POLL_INTERVAL: Duration = Duration::from_millis(50); pub const PRESENTATION_BUFFER_COUNT: usize = 10; #[derive(Debug, Deserialize, Serialize)] @@ -84,7 +83,6 @@ pub enum WebGPURequest { host_map: HostMap, map_range: std::ops::Range<u64>, }, - BufferMapComplete(id::BufferId), CommandEncoderFinish { command_encoder_id: id::CommandEncoderId, device_id: id::DeviceId, @@ -257,11 +255,6 @@ pub enum WebGPURequest { offset: u64, size: u64, }, - UpdateWebRenderData { - buffer_id: id::BufferId, - external_id: u64, - buffer_size: usize, - }, WriteBuffer { queue_id: id::QueueId, buffer_id: id::BufferId, @@ -281,14 +274,6 @@ pub enum WebGPURequest { }, } -struct BufferMapInfo<'a, T> { - buffer_id: id::BufferId, - sender: IpcSender<T>, - global: &'a wgpu::global::Global, - size: usize, - external_id: Option<u64>, -} - #[derive(Clone, Debug, Deserialize, Serialize)] pub struct WebGPU(pub IpcSender<(Option<ErrorScopeId>, WebGPURequest)>); @@ -353,35 +338,26 @@ impl WebGPU { } } -type WebGPUBufferMaps<'a> = - HashMap<id::BufferId, Rc<BufferMapInfo<'a, Option<WebGPUResponseResult>>>>; -type WebGPUPresentBufferMaps<'a> = - HashMap<id::BufferId, Rc<BufferMapInfo<'a, (Option<ErrorScopeId>, WebGPURequest)>>>; - #[allow(clippy::upper_case_acronyms)] // Name of the library -struct WGPU<'a> { +struct WGPU { receiver: IpcReceiver<(Option<ErrorScopeId>, WebGPURequest)>, sender: IpcSender<(Option<ErrorScopeId>, WebGPURequest)>, script_sender: IpcSender<WebGPUMsg>, - global: wgpu::global::Global, + global: Arc<wgpu::global::Global>, adapters: Vec<WebGPUAdapter>, devices: HashMap<WebGPUDevice, PipelineId>, // Track invalid adapters https://gpuweb.github.io/gpuweb/#invalid _invalid_adapters: Vec<WebGPUAdapter>, - // Buffers with pending mapping - buffer_maps: WebGPUBufferMaps<'a>, - // Presentation Buffers with pending mapping - present_buffer_maps: WebGPUPresentBufferMaps<'a>, //TODO: Remove this (https://github.com/gfx-rs/wgpu/issues/867) error_command_encoders: RefCell<HashMap<id::CommandEncoderId, String>>, - webrender_api: RenderApi, + webrender_api: Arc<Mutex<RenderApi>>, webrender_document: DocumentId, external_images: Arc<Mutex<WebrenderExternalImageRegistry>>, wgpu_image_map: Arc<Mutex<HashMap<u64, PresentationData>>>, last_poll: Instant, } -impl<'a> WGPU<'a> { +impl WGPU { fn new( receiver: IpcReceiver<(Option<ErrorScopeId>, WebGPURequest)>, sender: IpcSender<(Option<ErrorScopeId>, WebGPURequest)>, @@ -395,20 +371,18 @@ impl<'a> WGPU<'a> { receiver, sender, script_sender, - global: wgpu::global::Global::new( + global: Arc::new(wgpu::global::Global::new( "wgpu-core", InstanceDescriptor { backends: wgt::Backends::PRIMARY, ..Default::default() }, - ), + )), adapters: Vec::new(), devices: HashMap::new(), _invalid_adapters: Vec::new(), - buffer_maps: HashMap::new(), - present_buffer_maps: HashMap::new(), error_command_encoders: RefCell::new(HashMap::new()), - webrender_api: webrender_api_sender.create_api(), + webrender_api: Arc::new(Mutex::new(webrender_api_sender.create_api())), webrender_document, external_images, wgpu_image_map, @@ -416,13 +390,17 @@ impl<'a> WGPU<'a> { } } - fn run(&'a mut self) { + fn run(&mut self) { loop { - if self.last_poll.elapsed() >= Duration::from_millis(DEVICE_POLL_INTERVAL) { + let diff = DEVICE_POLL_INTERVAL.checked_sub(self.last_poll.elapsed()); + if diff.is_none() { let _ = self.global.poll_all_devices(false); self.last_poll = Instant::now(); } - if let Ok((scope_id, msg)) = self.receiver.try_recv() { + if let Ok((scope_id, msg)) = self + .receiver + .try_recv_timeout(diff.unwrap_or(DEVICE_POLL_INTERVAL)) + { match msg { WebGPURequest::BufferMapAsync { sender, @@ -431,54 +409,42 @@ impl<'a> WGPU<'a> { host_map, map_range, } => { - let map_info = BufferMapInfo { - buffer_id, - sender: sender.clone(), - global: &self.global, - size: (map_range.end - map_range.start) as usize, - external_id: None, - }; - self.buffer_maps.insert(buffer_id, Rc::new(map_info)); - // TODO(sagudev): replace with safe callback - unsafe extern "C" fn callback( - status: BufferMapAsyncStatus, - userdata: *mut u8, - ) { - let info = Rc::from_raw( - userdata as *const BufferMapInfo<Option<WebGPUResponseResult>>, - ); - let msg = match status { - BufferMapAsyncStatus::Success => { - let global = &info.global; - let (slice_pointer, range_size) = gfx_select!(info.buffer_id => - global.buffer_get_mapped_range(info.buffer_id, 0, None)) + let glob = Arc::clone(&self.global); + let resp_sender = sender.clone(); + let callback = BufferMapCallback::from_rust(Box::from(move |result| { + match result { + Ok(()) => { + let global = &glob; + let (slice_pointer, range_size) = gfx_select!(buffer_id => + global.buffer_get_mapped_range(buffer_id, 0, None)) .unwrap(); - let data = - slice::from_raw_parts(slice_pointer, range_size as usize); - Ok(WebGPUResponse::BufferMapAsync(IpcSharedMemory::from_bytes( - data, - ))) + // SAFETY: guarantee to be safe from wgpu + let data = unsafe { + slice::from_raw_parts(slice_pointer, range_size as usize) + }; + + if let Err(e) = + resp_sender.send(Some(Ok(WebGPUResponse::BufferMapAsync( + IpcSharedMemory::from_bytes(data), + )))) + { + warn!("Could not send BufferMapAsync Response ({})", e); + } }, - _ => { - warn!("Could not map buffer({:?})", info.buffer_id); - Err(String::from("Failed to map Buffer")) + Err(_) => { + warn!("Could not map buffer({:?})", buffer_id); + if let Err(e) = resp_sender + .send(Some(Err(String::from("Failed to map Buffer")))) + { + warn!("Could not send BufferMapAsync Response ({})", e); + } }, }; - if let Err(e) = info.sender.send(Some(msg)) { - warn!("Could not send BufferMapAsync Response ({})", e); - } - } + })); let operation = BufferMapOperation { host: host_map, - callback: unsafe { - Some(BufferMapCallback::from_c(BufferMapCallbackC { - callback, - user_data: convert_to_pointer( - self.buffer_maps.get(&buffer_id).unwrap().clone(), - ), - })) - }, + callback: Some(callback), }; let global = &self.global; let result = gfx_select!(buffer_id => global.buffer_map_async(buffer_id, map_range, operation)); @@ -489,9 +455,6 @@ impl<'a> WGPU<'a> { } self.send_result(device_id, scope_id, result); }, - WebGPURequest::BufferMapComplete(buffer_id) => { - self.buffer_maps.remove(&buffer_id); - }, WebGPURequest::CommandEncoderFinish { command_encoder_id, device_id, @@ -754,7 +717,8 @@ impl<'a> WGPU<'a> { let width = image_desc.size.width; let buffer_stride = ((width * 4) as u32 | (wgt::COPY_BYTES_PER_ROW_ALIGNMENT - 1)) + 1; - let image_key = self.webrender_api.generate_image_key(); + let mut wr = self.webrender_api.lock().unwrap(); + let image_key = wr.generate_image_key(); if let Err(e) = sender.send(image_key) { warn!("Failed to send ImageKey ({})", e); } @@ -783,8 +747,7 @@ impl<'a> WGPU<'a> { let mut txn = Transaction::new(); txn.add_image(image_key, image_desc, image_data, None); - self.webrender_api - .send_transaction(self.webrender_document, txn); + wr.send_transaction(self.webrender_document, txn); }, WebGPURequest::CreateTexture { device_id, @@ -855,6 +818,8 @@ impl<'a> WGPU<'a> { let mut txn = Transaction::new(); txn.delete_image(image_key); self.webrender_api + .lock() + .unwrap() .send_transaction(self.webrender_document, txn); }, WebGPURequest::DestroyTexture { @@ -1146,50 +1111,55 @@ impl<'a> WGPU<'a> { &[encoder_id.transmute()] )); - let map_info = BufferMapInfo { - buffer_id, - sender: self.sender.clone(), - global: &self.global, - size: buffer_size as usize, - external_id: Some(external_id), - }; - self.present_buffer_maps - .insert(buffer_id, Rc::new(map_info)); - // TODO(sagudev): replace with safe callback - unsafe extern "C" fn callback( - status: BufferMapAsyncStatus, - userdata: *mut u8, - ) { - let info = Rc::from_raw( - userdata - as *const BufferMapInfo<(Option<ErrorScopeId>, WebGPURequest)>, - ); - match status { - BufferMapAsyncStatus::Success => { - if let Err(e) = info.sender.send(( - None, - WebGPURequest::UpdateWebRenderData { - buffer_id: info.buffer_id, - buffer_size: info.size, - external_id: info.external_id.unwrap(), - }, - )) { - warn!("Could not send UpdateWebRenderData ({})", e); + let glob = Arc::clone(&self.global); + let wgpu_image_map = Arc::clone(&self.wgpu_image_map); + let webrender_api = Arc::clone(&self.webrender_api); + let webrender_document = self.webrender_document; + let callback = BufferMapCallback::from_rust(Box::from(move |result| { + match result { + Ok(()) => { + let global = &glob; + let (slice_pointer, range_size) = gfx_select!(buffer_id => + global.buffer_get_mapped_range(buffer_id, 0, Some(buffer_size as u64))) + .unwrap(); + let data = unsafe { + slice::from_raw_parts(slice_pointer, range_size as usize) } + .to_vec(); + if let Some(present_data) = + wgpu_image_map.lock().unwrap().get_mut(&external_id) + { + present_data.data = data; + let mut txn = Transaction::new(); + txn.update_image( + present_data.image_key, + present_data.image_desc, + present_data.image_data.clone(), + &DirtyRect::All, + ); + webrender_api + .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); + } else { + warn!( + "Data not found for ExternalImageId({:?})", + external_id + ); + } + let _ = + gfx_select!(buffer_id => global.buffer_unmap(buffer_id)); }, - _ => error!("Could not map buffer({:?})", info.buffer_id), + _ => error!("Could not map buffer({:?})", buffer_id), } - } + })); let map_op = BufferMapOperation { host: HostMap::Read, - callback: unsafe { - Some(BufferMapCallback::from_c(BufferMapCallbackC { - callback, - user_data: convert_to_pointer( - self.present_buffer_maps.get(&buffer_id).unwrap().clone(), - ), - })) - }, + callback: Some(callback), }; let _ = gfx_select!(buffer_id => global.buffer_map_async(buffer_id, 0..buffer_size, map_op)); }, @@ -1218,41 +1188,6 @@ impl<'a> WGPU<'a> { let result = gfx_select!(buffer_id => global.buffer_unmap(buffer_id)); self.send_result(device_id, scope_id, result); }, - WebGPURequest::UpdateWebRenderData { - buffer_id, - buffer_size, - external_id, - } => { - let global = &self.global; - let (slice_pointer, range_size) = gfx_select!(buffer_id => - global.buffer_get_mapped_range(buffer_id, 0, Some(buffer_size as u64))) - .unwrap(); - let data = - unsafe { slice::from_raw_parts(slice_pointer, range_size as usize) } - .to_vec(); - if let Some(present_data) = - self.wgpu_image_map.lock().unwrap().get_mut(&external_id) - { - present_data.data = data; - let mut txn = Transaction::new(); - txn.update_image( - present_data.image_key, - present_data.image_desc, - present_data.image_data.clone(), - &DirtyRect::All, - ); - self.webrender_api - .send_transaction(self.webrender_document, txn); - present_data - .queued_buffer_ids - .retain(|b_id| *b_id != buffer_id); - present_data.available_buffer_ids.push(buffer_id); - } else { - warn!("Data not found for ExternalImageId({:?})", external_id); - } - let _ = gfx_select!(buffer_id => global.buffer_unmap(buffer_id)); - self.present_buffer_maps.remove(&buffer_id); - }, WebGPURequest::WriteBuffer { queue_id, buffer_id, @@ -1440,10 +1375,6 @@ impl<'a> WGPU<'a> { } } -fn convert_to_pointer<T: Sized>(obj: Rc<T>) -> *mut u8 { - Rc::into_raw(obj) as *mut u8 -} - fn tuple_to_result<T, E>(res: (T, Option<E>)) -> Result<T, E> { if let Some(err) = res.1 { Err(err) |