aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--components/script/dom/gpubuffer.rs5
-rw-r--r--components/script/dom/gpucanvascontext.rs20
-rw-r--r--components/webgpu/lib.rs200
3 files changed, 153 insertions, 72 deletions
diff --git a/components/script/dom/gpubuffer.rs b/components/script/dom/gpubuffer.rs
index 724e22f6f53..c4dc472dc98 100644
--- a/components/script/dom/gpubuffer.rs
+++ b/components/script/dom/gpubuffer.rs
@@ -16,6 +16,7 @@ use crate::dom::promise::Promise;
use crate::realms::InRealm;
use crate::script_runtime::JSContext;
use dom_struct::dom_struct;
+use ipc_channel::ipc::IpcSharedMemory;
use js::jsapi::DetachArrayBuffer;
use js::jsapi::NewExternalArrayBuffer;
use js::jsapi::{Heap, JSObject};
@@ -150,7 +151,7 @@ impl GPUBufferMethods for GPUBuffer {
let m_range = m_info.mapping_range.clone();
if let Err(e) = self.channel.0.send(WebGPURequest::UnmapBuffer {
buffer_id: self.id().0,
- array_buffer: m_info.mapping.borrow().clone(),
+ array_buffer: IpcSharedMemory::from_bytes(m_info.mapping.borrow().as_slice()),
is_map_read: m_info.map_mode == Some(GPUMapModeConstants::READ),
offset: m_range.start,
size: m_range.end - m_range.start,
@@ -325,7 +326,7 @@ impl AsyncWGPUListener for GPUBuffer {
.as_mut()
.unwrap()
.mapping
- .borrow_mut() = bytes;
+ .borrow_mut() = bytes.to_vec();
promise.resolve_native(&());
self.state.set(GPUBufferState::Mapped);
},
diff --git a/components/script/dom/gpucanvascontext.rs b/components/script/dom/gpucanvascontext.rs
index 5c239fc5c8d..f7e3f06c5c8 100644
--- a/components/script/dom/gpucanvascontext.rs
+++ b/components/script/dom/gpucanvascontext.rs
@@ -18,12 +18,13 @@ use crate::dom::globalscope::GlobalScope;
use crate::dom::gpuswapchain::GPUSwapChain;
use crate::dom::htmlcanvaselement::{HTMLCanvasElement, LayoutCanvasRenderingContextHelpers};
use crate::dom::node::{document_from_node, Node, NodeDamage};
+use arrayvec::ArrayVec;
use dom_struct::dom_struct;
use euclid::default::Size2D;
use ipc_channel::ipc;
use script_layout_interface::HTMLCanvasDataSource;
use std::cell::Cell;
-use webgpu::{wgt, WebGPU, WebGPURequest};
+use webgpu::{wgpu::id, wgt, WebGPU, WebGPURequest};
#[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, Ord, PartialEq, PartialOrd)]
pub struct WebGPUContextId(pub u64);
@@ -91,7 +92,6 @@ impl GPUCanvasContext {
external_id: self.context_id.0,
texture_id,
encoder_id,
- image_key: self.webrender_image.get().unwrap(),
}) {
warn!(
"Failed to send UpdateWebrenderData({:?}) ({})",
@@ -130,11 +130,15 @@ impl GPUCanvasContextMethods for GPUCanvasContext {
}
*self.swap_chain.borrow_mut() = None;
- let buffer_id = self
- .global()
- .wgpu_id_hub()
- .lock()
- .create_buffer_id(descriptor.device.id().0.backend());
+ let mut buffer_ids = ArrayVec::<[id::BufferId; 5]>::new();
+ for _ in 0..5 {
+ buffer_ids.push(
+ self.global()
+ .wgpu_id_hub()
+ .lock()
+ .create_buffer_id(descriptor.device.id().0.backend()),
+ );
+ }
let image_desc = webrender_api::ImageDescriptor {
format: match descriptor.format {
@@ -166,7 +170,7 @@ impl GPUCanvasContextMethods for GPUCanvasContext {
.0
.send(WebGPURequest::CreateSwapChain {
device_id: descriptor.device.id().0,
- buffer_id,
+ buffer_ids,
external_id: self.context_id.0,
sender,
image_desc,
diff --git a/components/webgpu/lib.rs b/components/webgpu/lib.rs
index 71f5e633e6b..0f8d1fa29f9 100644
--- a/components/webgpu/lib.rs
+++ b/components/webgpu/lib.rs
@@ -13,7 +13,7 @@ pub mod identity;
use arrayvec::ArrayVec;
use euclid::default::Size2D;
use identity::{IdentityRecyclerFactory, WebGPUMsg};
-use ipc_channel::ipc::{self, IpcReceiver, IpcSender};
+use ipc_channel::ipc::{self, IpcReceiver, IpcSender, IpcSharedMemory};
use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
use serde::{Deserialize, Serialize};
use servo_config::pref;
@@ -51,7 +51,7 @@ pub enum WebGPUResponse {
queue_id: WebGPUQueue,
_descriptor: wgt::DeviceDescriptor,
},
- BufferMapAsync(Vec<u8>),
+ BufferMapAsync(IpcSharedMemory),
}
pub type WebGPUResponseResult = Result<WebGPUResponse, String>;
@@ -145,7 +145,7 @@ pub enum WebGPURequest {
},
CreateSwapChain {
device_id: id::DeviceId,
- buffer_id: id::BufferId,
+ buffer_ids: ArrayVec<[id::BufferId; 5]>,
external_id: u64,
sender: IpcSender<webrender_api::ImageKey>,
image_desc: webrender_api::ImageDescriptor,
@@ -195,15 +195,19 @@ pub enum WebGPURequest {
external_id: u64,
texture_id: id::TextureId,
encoder_id: id::CommandEncoderId,
- image_key: webrender_api::ImageKey,
},
UnmapBuffer {
buffer_id: id::BufferId,
- array_buffer: Vec<u8>,
+ array_buffer: IpcSharedMemory,
is_map_read: bool,
offset: u64,
size: u64,
},
+ UpdateWebRenderData {
+ buffer_id: id::BufferId,
+ external_id: u64,
+ buffer_size: usize,
+ },
}
#[derive(Debug, Deserialize, Serialize)]
@@ -213,11 +217,12 @@ pub enum WebGPUBindings {
TextureView(id::TextureViewId),
}
-struct BufferMapInfo<'a> {
+struct BufferMapInfo<'a, T> {
buffer_id: id::BufferId,
- sender: IpcSender<WebGPUResponseResult>,
+ sender: IpcSender<T>,
global: &'a wgpu::hub::Global<IdentityRecyclerFactory>,
size: usize,
+ external_id: Option<u64>,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
@@ -294,7 +299,9 @@ struct WGPU<'a> {
// Track invalid adapters https://gpuweb.github.io/gpuweb/#invalid
_invalid_adapters: Vec<WebGPUAdapter>,
// Buffers with pending mapping
- buffer_maps: HashMap<id::BufferId, BufferMapInfo<'a>>,
+ buffer_maps: HashMap<id::BufferId, BufferMapInfo<'a, WebGPUResponseResult>>,
+ // Presentation Buffers with pending mapping
+ present_buffer_maps: HashMap<id::BufferId, BufferMapInfo<'a, WebGPURequest>>,
webrender_api: webrender_api::RenderApi,
webrender_document: webrender_api::DocumentId,
external_images: Arc<Mutex<WebrenderExternalImageRegistry>>,
@@ -324,6 +331,7 @@ impl<'a> WGPU<'a> {
devices: Vec::new(),
_invalid_adapters: Vec::new(),
buffer_maps: HashMap::new(),
+ present_buffer_maps: HashMap::new(),
webrender_api: webrender_api_sender.create_api(),
webrender_document,
external_images,
@@ -351,6 +359,7 @@ impl<'a> WGPU<'a> {
sender,
global: &self.global,
size: (map_range.end - map_range.start) as usize,
+ external_id: None,
};
self.buffer_maps.insert(buffer_id, map_info);
@@ -359,16 +368,19 @@ impl<'a> WGPU<'a> {
userdata: *mut u8,
) {
let nonnull_info =
- NonNull::new(userdata as *mut BufferMapInfo).unwrap();
+ NonNull::new(userdata as *mut BufferMapInfo<WebGPUResponseResult>)
+ .unwrap();
let info = nonnull_info.as_ref();
match status {
BufferMapAsyncStatus::Success => {
let global = &info.global;
let data_pt = gfx_select!(info.buffer_id =>
global.buffer_get_mapped_range(info.buffer_id, 0, None));
- let data = slice::from_raw_parts(data_pt, info.size).to_vec();
+ let data = slice::from_raw_parts(data_pt, info.size);
if let Err(e) =
- info.sender.send(Ok(WebGPUResponse::BufferMapAsync(data)))
+ info.sender.send(Ok(WebGPUResponse::BufferMapAsync(
+ IpcSharedMemory::from_bytes(data),
+ )))
{
warn!("Could not send BufferMapAsync Response ({})", e);
}
@@ -620,7 +632,7 @@ impl<'a> WGPU<'a> {
},
WebGPURequest::CreateSwapChain {
device_id,
- buffer_id,
+ buffer_ids,
external_id,
sender,
image_desc,
@@ -630,6 +642,10 @@ 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();
+ if let Err(e) = sender.send(image_key) {
+ warn!("Failed to send ImageKey ({})", e);
+ }
let _ = self.wgpu_image_map.lock().unwrap().insert(
external_id,
PresentationData {
@@ -637,30 +653,15 @@ impl<'a> WGPU<'a> {
queue_id: device_id,
data: vec![255; (buffer_stride * height as u32) as usize],
size: Size2D::new(width, height),
- buffer_id,
+ unassigned_buffer_ids: buffer_ids,
+ available_buffer_ids: ArrayVec::<[id::BufferId; 5]>::new(),
+ queued_buffer_ids: ArrayVec::<[id::BufferId; 5]>::new(),
buffer_stride,
+ image_key,
image_desc,
image_data: image_data.clone(),
},
);
- let buffer_size = (buffer_stride * height as u32) as wgt::BufferAddress;
- let global = &self.global;
- let buffer_desc = wgt::BufferDescriptor {
- label: ptr::null(),
- size: buffer_size,
- usage: wgt::BufferUsage::MAP_READ | wgt::BufferUsage::COPY_DST,
- mapped_at_creation: false,
- };
- let _ = gfx_select!(buffer_id => global.device_create_buffer(
- device_id,
- &buffer_desc,
- buffer_id
- ));
-
- let image_key = self.webrender_api.generate_image_key();
- if let Err(e) = sender.send(image_key) {
- warn!("Failed to send ImageKey ({})", e);
- }
let mut txn = webrender_api::Transaction::new();
txn.add_image(image_key, image_desc, image_data, None);
@@ -708,7 +709,17 @@ impl<'a> WGPU<'a> {
.remove(&external_id)
.unwrap();
let global = &self.global;
- gfx_select!(data.buffer_id => global.buffer_destroy(data.buffer_id));
+ for b_id in data.available_buffer_ids.iter() {
+ gfx_select!(b_id => global.buffer_destroy(*b_id));
+ }
+ for b_id in data.queued_buffer_ids.iter() {
+ gfx_select!(b_id => global.buffer_destroy(*b_id));
+ }
+ for b_id in data.unassigned_buffer_ids.iter() {
+ if let Err(e) = self.script_sender.send(WebGPUMsg::FreeBuffer(*b_id)) {
+ warn!("Unable to send FreeBuffer({:?}) ({:?})", *b_id, e);
+ };
+ }
let mut txn = webrender_api::Transaction::new();
txn.delete_image(image_key);
self.webrender_api
@@ -829,7 +840,6 @@ impl<'a> WGPU<'a> {
external_id,
texture_id,
encoder_id,
- image_key,
} => {
let global = &self.global;
let device_id;
@@ -844,8 +854,36 @@ impl<'a> WGPU<'a> {
size = present_data.size;
device_id = present_data.device_id;
queue_id = present_data.queue_id;
- buffer_id = present_data.buffer_id;
buffer_stride = present_data.buffer_stride;
+ buffer_id = if let Some(b_id) =
+ present_data.available_buffer_ids.pop()
+ {
+ b_id
+ } else if let Some(b_id) = present_data.unassigned_buffer_ids.pop()
+ {
+ let buffer_size =
+ (buffer_stride * size.height as u32) as wgt::BufferAddress;
+ let buffer_desc = wgt::BufferDescriptor {
+ label: ptr::null(),
+ size: buffer_size,
+ usage: wgt::BufferUsage::MAP_READ |
+ wgt::BufferUsage::COPY_DST,
+ mapped_at_creation: false,
+ };
+ let _ = gfx_select!(b_id => global.device_create_buffer(
+ device_id,
+ &buffer_desc,
+ b_id
+ ));
+ b_id
+ } else {
+ warn!(
+ "No staging buffer available for ExternalImageId({:?})",
+ external_id
+ );
+ continue;
+ };
+ present_data.queued_buffer_ids.push(buffer_id);
} else {
warn!("Data not found for ExternalImageId({:?})", external_id);
continue;
@@ -893,43 +931,46 @@ impl<'a> WGPU<'a> {
queue_id,
&[encoder_id]
));
- extern "C" fn callback(status: BufferMapAsyncStatus, _user_data: *mut u8) {
+
+ 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, map_info);
+ unsafe extern "C" fn callback(
+ status: BufferMapAsyncStatus,
+ userdata: *mut u8,
+ ) {
+ let nonnull_info =
+ NonNull::new(userdata as *mut BufferMapInfo<WebGPURequest>)
+ .unwrap();
+ let info = nonnull_info.as_ref();
match status {
BufferMapAsyncStatus::Success => {
- debug!("Buffer Mapped");
+ if let Err(e) =
+ info.sender.send(WebGPURequest::UpdateWebRenderData {
+ buffer_id: info.buffer_id,
+ buffer_size: info.size,
+ external_id: info.external_id.unwrap(),
+ })
+ {
+ warn!("Could not send UpdateWebRenderData ({})", e);
+ }
},
- _ => warn!("Could not map buffer"),
+ _ => error!("Could not map buffer({:?})", info.buffer_id),
}
}
let map_op = BufferMapOperation {
host: HostMap::Read,
callback,
- user_data: ptr::null_mut(),
+ user_data: convert_to_pointer(
+ self.present_buffer_maps.get(&buffer_id).unwrap(),
+ ),
};
gfx_select!(buffer_id => global.buffer_map_async(buffer_id, 0..buffer_size, map_op));
- // TODO: Remove the blocking behaviour
- gfx_select!(device_id => global.device_poll(device_id, true));
- let buf_data = gfx_select!(buffer_id =>
- global.buffer_get_mapped_range(buffer_id, 0, None));
- if let Some(present_data) =
- self.wgpu_image_map.lock().unwrap().get_mut(&external_id)
- {
- present_data.data = unsafe {
- slice::from_raw_parts(buf_data, buffer_size as usize).to_vec()
- };
- let mut txn = webrender_api::Transaction::new();
- txn.update_image(
- image_key,
- present_data.image_desc,
- present_data.image_data.clone(),
- &webrender_api::DirtyRect::All,
- );
- self.webrender_api
- .send_transaction(self.webrender_document, txn);
- } else {
- warn!("Data not found for ExternalImageId({:?})", external_id);
- }
- gfx_select!(buffer_id => global.buffer_unmap(buffer_id));
},
WebGPURequest::UnmapBuffer {
buffer_id,
@@ -950,6 +991,38 @@ impl<'a> WGPU<'a> {
}
gfx_select!(buffer_id => global.buffer_unmap(buffer_id));
},
+ WebGPURequest::UpdateWebRenderData {
+ buffer_id,
+ buffer_size,
+ external_id,
+ } => {
+ let global = &self.global;
+ let data_pt = gfx_select!(buffer_id =>
+ global.buffer_get_mapped_range(buffer_id, 0, None));
+ let data = unsafe { slice::from_raw_parts(data_pt, buffer_size) }.to_vec();
+ if let Some(present_data) =
+ self.wgpu_image_map.lock().unwrap().get_mut(&external_id)
+ {
+ present_data.data = data;
+ let mut txn = webrender_api::Transaction::new();
+ txn.update_image(
+ present_data.image_key,
+ present_data.image_desc,
+ present_data.image_data.clone(),
+ &webrender_api::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);
+ }
+ gfx_select!(buffer_id => global.buffer_unmap(buffer_id));
+ self.present_buffer_maps.remove(&buffer_id);
+ },
}
}
}
@@ -1034,8 +1107,11 @@ pub struct PresentationData {
queue_id: id::QueueId,
pub data: Vec<u8>,
pub size: Size2D<i32>,
- buffer_id: id::BufferId,
+ unassigned_buffer_ids: ArrayVec<[id::BufferId; 5]>,
+ available_buffer_ids: ArrayVec<[id::BufferId; 5]>,
+ queued_buffer_ids: ArrayVec<[id::BufferId; 5]>,
buffer_stride: u32,
+ image_key: webrender_api::ImageKey,
image_desc: webrender_api::ImageDescriptor,
image_data: webrender_api::ImageData,
}