webgpu: Sync GPUBuffer (#33154)

* More helpers on `Promise`

Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com>

* Sync `GPUBuffer`

Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com>

* Set some good expectations

Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com>

* Some bad expect

also on firefox

Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com>

* Extract DataBlock, DataView impl from GPUBuffer

Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com>

* Fix size check to work on 32bit platforms

Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com>

---------

Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com>
This commit is contained in:
Samson 2024-08-27 09:54:55 +02:00 committed by GitHub
parent bb5926b329
commit 7fce24f9d5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
12 changed files with 690 additions and 1163 deletions

View file

@ -267,9 +267,8 @@ pub enum WebGPURequest {
},
UnmapBuffer {
buffer_id: id::BufferId,
device_id: id::DeviceId,
array_buffer: IpcSharedMemory,
is_map_read: bool,
write_back: bool,
offset: u64,
size: u64,
},

View file

@ -4,10 +4,13 @@
//! IPC messages that are send to WebGPU DOM objects.
use std::ops::Range;
use ipc_channel::ipc::IpcSharedMemory;
use serde::{Deserialize, Serialize};
use wgc::id;
use wgc::pipeline::CreateShaderModuleError;
use wgpu_core::device::HostMap;
use wgpu_core::instance::{RequestAdapterError, RequestDeviceError};
use wgpu_core::resource::BufferAccessError;
pub use {wgpu_core as wgc, wgpu_types as wgt};
@ -72,6 +75,13 @@ pub struct Pipeline<T: std::fmt::Debug + Serialize> {
pub label: String,
}
#[derive(Debug, Deserialize, Serialize)]
pub struct Mapping {
pub data: IpcSharedMemory,
pub mode: HostMap,
pub range: Range<u64>,
}
#[derive(Debug, Deserialize, Serialize)]
#[allow(clippy::large_enum_variant)]
pub enum WebGPUResponse {
@ -85,7 +95,7 @@ pub enum WebGPUResponse {
Result<wgt::DeviceDescriptor<Option<String>>, RequestDeviceError>,
),
),
BufferMapAsync(Result<IpcSharedMemory, BufferAccessError>),
BufferMapAsync(Result<Mapping, BufferAccessError>),
SubmittedWorkDone,
PoppedErrorScope(Result<Option<Error>, PopError>),
CompilationInfo(Option<ShaderCompilationInfo>),

View file

@ -40,8 +40,8 @@ use crate::gpu_error::ErrorScope;
use crate::poll_thread::Poller;
use crate::render_commands::apply_render_command;
use crate::{
Adapter, ComputePassId, Error, Pipeline, PopError, PresentationData, RenderPassId, WebGPU,
WebGPUAdapter, WebGPUDevice, WebGPUMsg, WebGPUQueue, WebGPURequest, WebGPUResponse,
Adapter, ComputePassId, Error, Mapping, Pipeline, PopError, PresentationData, RenderPassId,
WebGPU, WebGPUAdapter, WebGPUDevice, WebGPUMsg, WebGPUQueue, WebGPURequest, WebGPUResponse,
};
pub const PRESENTATION_BUFFER_COUNT: usize = 10;
@ -191,11 +191,11 @@ impl WGPU {
let callback = BufferMapCallback::from_rust(Box::from(
move |result: BufferAccessResult| {
drop(token);
let response = result.map(|_| {
let response = result.and_then(|_| {
let global = &glob;
let (slice_pointer, range_size) = gfx_select!(buffer_id =>
global.buffer_get_mapped_range(buffer_id, 0, None))
.unwrap();
global.buffer_get_mapped_range(buffer_id, offset, size))
?;
// SAFETY: guarantee to be safe from wgpu
let data = unsafe {
slice::from_raw_parts(
@ -204,7 +204,11 @@ impl WGPU {
)
};
IpcSharedMemory::from_bytes(data)
Ok(Mapping {
data: IpcSharedMemory::from_bytes(data),
range: offset..offset + range_size,
mode: host_map,
})
});
if let Err(e) =
resp_sender.send(WebGPUResponse::BufferMapAsync(response))
@ -226,13 +230,6 @@ impl WGPU {
operation
));
self.poller.wake();
if let Err(e) = &result {
if let Err(w) =
sender.send(WebGPUResponse::BufferMapAsync(Err(e.to_owned())))
{
warn!("Failed to send BufferMapAsync Response ({:?})", w);
}
}
// Per spec we also need to raise validation error here
self.maybe_dispatch_wgpu_error(device_id, result.err());
},
@ -1208,31 +1205,31 @@ impl WGPU {
},
WebGPURequest::UnmapBuffer {
buffer_id,
device_id,
array_buffer,
is_map_read,
write_back,
offset,
size,
} => {
let global = &self.global;
if !is_map_read {
let (slice_pointer, range_size) =
gfx_select!(buffer_id => global.buffer_get_mapped_range(
if write_back {
if let Ok((slice_pointer, range_size)) = gfx_select!(
buffer_id => global.buffer_get_mapped_range(
buffer_id,
offset,
Some(size)
))
.unwrap();
unsafe {
slice::from_raw_parts_mut(
slice_pointer.as_ptr(),
range_size as usize,
)
) {
unsafe {
slice::from_raw_parts_mut(
slice_pointer.as_ptr(),
range_size as usize,
)
}
.copy_from_slice(&array_buffer);
}
.copy_from_slice(&array_buffer);
}
let result = gfx_select!(buffer_id => global.buffer_unmap(buffer_id));
self.maybe_dispatch_wgpu_error(device_id, result.err());
// Ignore result because this operation always succeed from user perspective
let _result = gfx_select!(buffer_id => global.buffer_unmap(buffer_id));
},
WebGPURequest::WriteBuffer {
device_id,