Implement Droppable struct for gpubuffer

Signed-off-by: Domenico Rizzo <domenico.rizzo@gmail.com>

Corrected member access

Signed-off-by: Domenico Rizzo <domenico.rizzo@gmail.com>

removing unwanted macro

Signed-off-by: Domenico Rizzo <domenico.rizzo@gmail.com>

Corrected methods' name

Signed-off-by: Domenico Rizzo <domenico.rizzo@gmail.com>

applied mach fmt

Signed-off-by: Domenico Rizzo <domenico.rizzo@gmail.com>
This commit is contained in:
Domenico Rizzo 2025-05-07 17:50:16 +02:00
parent bc9f55bcc9
commit 627834fcbc

View file

@ -66,22 +66,13 @@ impl ActiveBufferMapping {
#[dom_struct] #[dom_struct]
pub(crate) struct GPUBuffer { pub(crate) struct GPUBuffer {
reflector_: Reflector, reflector_: Reflector,
#[ignore_malloc_size_of = "defined in webgpu"]
#[no_trace]
channel: WebGPU,
label: DomRefCell<USVString>, label: DomRefCell<USVString>,
#[no_trace]
buffer: WebGPUBuffer,
device: Dom<GPUDevice>, device: Dom<GPUDevice>,
/// <https://gpuweb.github.io/gpuweb/#dom-gpubuffer-size> /// <https://gpuweb.github.io/gpuweb/#dom-gpubuffer-size>
size: GPUSize64, size: GPUSize64,
/// <https://gpuweb.github.io/gpuweb/#dom-gpubuffer-usage> /// <https://gpuweb.github.io/gpuweb/#dom-gpubuffer-usage>
usage: GPUFlagsConstant, usage: GPUFlagsConstant,
/// <https://gpuweb.github.io/gpuweb/#dom-gpubuffer-pending_map-slot> droppable: DroppableGPUBuffer,
#[ignore_malloc_size_of = "promises are hard"]
pending_map: DomRefCell<Option<Rc<Promise>>>,
/// <https://gpuweb.github.io/gpuweb/#dom-gpubuffer-mapping-slot>
mapping: DomRefCell<Option<ActiveBufferMapping>>,
} }
impl GPUBuffer { impl GPUBuffer {
@ -96,14 +87,16 @@ impl GPUBuffer {
) -> Self { ) -> Self {
Self { Self {
reflector_: Reflector::new(), reflector_: Reflector::new(),
channel,
label: DomRefCell::new(label), label: DomRefCell::new(label),
device: Dom::from_ref(device), device: Dom::from_ref(device),
buffer,
pending_map: DomRefCell::new(None),
size, size,
usage, usage,
mapping: DomRefCell::new(mapping), droppable: DroppableGPUBuffer::new(
channel,
buffer,
DomRefCell::new(None),
DomRefCell::new(mapping),
),
} }
} }
@ -131,7 +124,7 @@ impl GPUBuffer {
impl GPUBuffer { impl GPUBuffer {
pub(crate) fn id(&self) -> WebGPUBuffer { pub(crate) fn id(&self) -> WebGPUBuffer {
self.buffer self.droppable.buffer
} }
/// <https://gpuweb.github.io/gpuweb/#dom-gpudevice-createbuffer> /// <https://gpuweb.github.io/gpuweb/#dom-gpudevice-createbuffer>
@ -182,62 +175,16 @@ impl GPUBuffer {
} }
} }
impl Drop for GPUBuffer {
fn drop(&mut self) {
self.Destroy()
}
}
impl GPUBufferMethods<crate::DomTypeHolder> for GPUBuffer { impl GPUBufferMethods<crate::DomTypeHolder> for GPUBuffer {
#[allow(unsafe_code)] #[allow(unsafe_code)]
/// <https://gpuweb.github.io/gpuweb/#dom-gpubuffer-unmap> /// <https://gpuweb.github.io/gpuweb/#dom-gpubuffer-unmap>
fn Unmap(&self) { fn Unmap(&self) {
// Step 1 self.droppable.unmap()
if let Some(promise) = self.pending_map.borrow_mut().take() {
promise.reject_error(Error::Abort, CanGc::note());
}
// Step 2
let mut mapping = self.mapping.borrow_mut().take();
let mapping = if let Some(mapping) = mapping.as_mut() {
mapping
} else {
return;
};
// Step 3
mapping.data.clear_views();
// Step 5&7
if let Err(e) = self.channel.0.send(WebGPURequest::UnmapBuffer {
buffer_id: self.id().0,
mapping: if mapping.mode >= GPUMapModeConstants::WRITE {
Some(Mapping {
data: IpcSharedMemory::from_bytes(mapping.data.data()),
range: mapping.range.clone(),
mode: HostMap::Write,
})
} else {
None
},
}) {
warn!("Failed to send Buffer unmap ({:?}) ({})", self.buffer.0, e);
}
} }
/// <https://gpuweb.github.io/gpuweb/#dom-gpubuffer-destroy> /// <https://gpuweb.github.io/gpuweb/#dom-gpubuffer-destroy>
fn Destroy(&self) { fn Destroy(&self) {
// Step 1 self.droppable.destroy()
self.Unmap();
// Step 2
if let Err(e) = self
.channel
.0
.send(WebGPURequest::DestroyBuffer(self.buffer.0))
{
warn!(
"Failed to send WebGPURequest::DestroyBuffer({:?}) ({})",
self.buffer.0, e
);
};
} }
/// <https://gpuweb.github.io/gpuweb/#dom-gpubuffer-mapasync> /// <https://gpuweb.github.io/gpuweb/#dom-gpubuffer-mapasync>
@ -251,12 +198,12 @@ impl GPUBufferMethods<crate::DomTypeHolder> for GPUBuffer {
) -> Rc<Promise> { ) -> Rc<Promise> {
let promise = Promise::new_in_current_realm(comp, can_gc); let promise = Promise::new_in_current_realm(comp, can_gc);
// Step 2 // Step 2
if self.pending_map.borrow().is_some() { if self.droppable.pending_map.borrow().is_some() {
promise.reject_error(Error::Operation, can_gc); promise.reject_error(Error::Operation, can_gc);
return promise; return promise;
} }
// Step 4 // Step 4
*self.pending_map.borrow_mut() = Some(promise.clone()); *self.droppable.pending_map.borrow_mut() = Some(promise.clone());
// Step 5 // Step 5
let host_map = match mode { let host_map = match mode {
GPUMapModeConstants::READ => HostMap::Read, GPUMapModeConstants::READ => HostMap::Read,
@ -276,17 +223,22 @@ impl GPUBufferMethods<crate::DomTypeHolder> for GPUBuffer {
self, self,
self.global().task_manager().dom_manipulation_task_source(), self.global().task_manager().dom_manipulation_task_source(),
); );
if let Err(e) = self.channel.0.send(WebGPURequest::BufferMapAsync { if let Err(e) = self
sender, .droppable
buffer_id: self.buffer.0, .channel
device_id: self.device.id().0, .0
host_map, .send(WebGPURequest::BufferMapAsync {
offset, sender,
size, buffer_id: self.droppable.buffer.0,
}) { device_id: self.device.id().0,
host_map,
offset,
size,
})
{
warn!( warn!(
"Failed to send BufferMapAsync ({:?}) ({})", "Failed to send BufferMapAsync ({:?}) ({})",
self.buffer.0, e self.droppable.buffer.0, e
); );
self.map_failure(&promise, can_gc); self.map_failure(&promise, can_gc);
return promise; return promise;
@ -310,7 +262,7 @@ impl GPUBufferMethods<crate::DomTypeHolder> for GPUBuffer {
self.size.saturating_sub(offset) self.size.saturating_sub(offset)
}; };
// Step 2: validation // Step 2: validation
let mut mapping = self.mapping.borrow_mut(); let mut mapping = self.droppable.mapping.borrow_mut();
let mapping = mapping.as_mut().ok_or(Error::Operation)?; let mapping = mapping.as_mut().ok_or(Error::Operation)?;
let valid = offset % wgpu_types::MAP_ALIGNMENT == 0 && let valid = offset % wgpu_types::MAP_ALIGNMENT == 0 &&
@ -355,9 +307,9 @@ impl GPUBufferMethods<crate::DomTypeHolder> for GPUBuffer {
/// <https://gpuweb.github.io/gpuweb/#dom-gpubuffer-mapstate> /// <https://gpuweb.github.io/gpuweb/#dom-gpubuffer-mapstate>
fn MapState(&self) -> GPUBufferMapState { fn MapState(&self) -> GPUBufferMapState {
// Step 1&2&3 // Step 1&2&3
if self.mapping.borrow().is_some() { if self.droppable.mapping.borrow().is_some() {
GPUBufferMapState::Mapped GPUBufferMapState::Mapped
} else if self.pending_map.borrow().is_some() { } else if self.droppable.pending_map.borrow().is_some() {
GPUBufferMapState::Pending GPUBufferMapState::Pending
} else { } else {
GPUBufferMapState::Unmapped GPUBufferMapState::Unmapped
@ -367,7 +319,7 @@ impl GPUBufferMethods<crate::DomTypeHolder> for GPUBuffer {
impl GPUBuffer { impl GPUBuffer {
fn map_failure(&self, p: &Rc<Promise>, can_gc: CanGc) { fn map_failure(&self, p: &Rc<Promise>, can_gc: CanGc) {
let mut pending_map = self.pending_map.borrow_mut(); let mut pending_map = self.droppable.pending_map.borrow_mut();
// Step 1 // Step 1
if pending_map.as_ref() != Some(p) { if pending_map.as_ref() != Some(p) {
assert!(p.is_rejected()); assert!(p.is_rejected());
@ -386,7 +338,7 @@ impl GPUBuffer {
} }
fn map_success(&self, p: &Rc<Promise>, wgpu_mapping: Mapping, can_gc: CanGc) { fn map_success(&self, p: &Rc<Promise>, wgpu_mapping: Mapping, can_gc: CanGc) {
let mut pending_map = self.pending_map.borrow_mut(); let mut pending_map = self.droppable.pending_map.borrow_mut();
// Step 1 // Step 1
if pending_map.as_ref() != Some(p) { if pending_map.as_ref() != Some(p) {
@ -415,7 +367,7 @@ impl GPUBuffer {
// Step 5 // Step 5
mapping.data.load(&wgpu_mapping.data); mapping.data.load(&wgpu_mapping.data);
// Step 6 // Step 6
self.mapping.borrow_mut().replace(mapping); self.droppable.mapping.borrow_mut().replace(mapping);
// Step 7 // Step 7
pending_map.take(); pending_map.take();
p.resolve_native(&(), can_gc); p.resolve_native(&(), can_gc);
@ -437,3 +389,92 @@ impl RoutedPromiseListener<Result<Mapping, BufferAccessError>> for GPUBuffer {
} }
} }
} }
#[derive(JSTraceable, MallocSizeOf)]
pub(crate) struct DroppableGPUBuffer {
#[ignore_malloc_size_of = "defined in webgpu"]
#[no_trace]
pub(crate) channel: WebGPU,
#[no_trace]
pub(crate) buffer: WebGPUBuffer,
/// <https://gpuweb.github.io/gpuweb/#dom-gpubuffer-pending_map-slot>
#[ignore_malloc_size_of = "promises are hard"]
pub(crate) pending_map: DomRefCell<Option<Rc<Promise>>>,
/// <https://gpuweb.github.io/gpuweb/#dom-gpubuffer-mapping-slot>
pub(crate) mapping: DomRefCell<Option<ActiveBufferMapping>>,
}
impl DroppableGPUBuffer {
pub(crate) fn new(
channel: WebGPU,
buffer: WebGPUBuffer,
pending_map: DomRefCell<Option<Rc<Promise>>>,
mapping: DomRefCell<Option<ActiveBufferMapping>>,
) -> Self {
Self {
channel,
buffer,
pending_map,
mapping,
}
}
}
impl DroppableGPUBuffer {
#[allow(unsafe_code)]
/// <https://gpuweb.github.io/gpuweb/#dom-gpubuffer-unmap>
pub(crate) fn unmap(&self) {
// Step 1
if let Some(promise) = self.pending_map.borrow_mut().take() {
promise.reject_error(Error::Abort, CanGc::note());
}
// Step 2
let mut mapping = self.mapping.borrow_mut().take();
let mapping = if let Some(mapping) = mapping.as_mut() {
mapping
} else {
return;
};
// Step 3
mapping.data.clear_views();
// Step 5&7
if let Err(e) = self.channel.0.send(WebGPURequest::UnmapBuffer {
buffer_id: self.buffer.0,
mapping: if mapping.mode >= GPUMapModeConstants::WRITE {
Some(Mapping {
data: IpcSharedMemory::from_bytes(mapping.data.data()),
range: mapping.range.clone(),
mode: HostMap::Write,
})
} else {
None
},
}) {
warn!("Failed to send Buffer unmap ({:?}) ({})", self.buffer.0, e);
}
}
/// <https://gpuweb.github.io/gpuweb/#dom-gpubuffer-destroy>
pub(crate) fn destroy(&self) {
// Step 1
self.unmap();
// Step 2
if let Err(e) = self
.channel
.0
.send(WebGPURequest::DestroyBuffer(self.buffer.0))
{
warn!(
"Failed to send WebGPURequest::DestroyBuffer({:?}) ({})",
self.buffer.0, e
);
};
}
}
impl Drop for DroppableGPUBuffer {
fn drop(&mut self) {
self.destroy()
}
}