Files
servo/components/script/dom/webgpu/gpucomputepassencoder.rs
Sam 8ed35f1ce9 script: Add basic memory pressure reporting to SpiderMonkey (#42180)
By reporting memory usage of rust objects back to SM it can trigger GC
sooner and release more memory (I hope that we could use this to avoid
OOB in webgpu in the future).

Currently we use simple `size_of::<DomStruct>() +
size_of::<Box<DomStruct>>()` but it's possible to override reported
memory with `update_memory_size(self, nbytes);` on reflector. This is
mostly useful for canvases and buffers which usually have large
associated data.

Testing: None, but I am wondering if we can connect this to
`about:memory`.
Fixes: #42168

---------

Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com>
2026-01-30 18:11:06 +00:00

162 lines
5.5 KiB
Rust

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use dom_struct::dom_struct;
use webgpu_traits::{WebGPU, WebGPUComputePass, WebGPURequest};
use crate::dom::bindings::cell::DomRefCell;
use crate::dom::bindings::codegen::Bindings::WebGPUBinding::GPUComputePassEncoderMethods;
use crate::dom::bindings::reflector::{Reflector, reflect_dom_object};
use crate::dom::bindings::root::{Dom, DomRoot};
use crate::dom::bindings::str::USVString;
use crate::dom::globalscope::GlobalScope;
use crate::dom::webgpu::gpubindgroup::GPUBindGroup;
use crate::dom::webgpu::gpubuffer::GPUBuffer;
use crate::dom::webgpu::gpucommandencoder::GPUCommandEncoder;
use crate::dom::webgpu::gpucomputepipeline::GPUComputePipeline;
use crate::script_runtime::CanGc;
#[dom_struct]
pub(crate) struct GPUComputePassEncoder {
reflector_: Reflector,
#[ignore_malloc_size_of = "defined in webgpu"]
#[no_trace]
channel: WebGPU,
label: DomRefCell<USVString>,
#[no_trace]
compute_pass: WebGPUComputePass,
command_encoder: Dom<GPUCommandEncoder>,
}
impl GPUComputePassEncoder {
fn new_inherited(
channel: WebGPU,
parent: &GPUCommandEncoder,
compute_pass: WebGPUComputePass,
label: USVString,
) -> Self {
Self {
channel,
reflector_: Reflector::new(),
label: DomRefCell::new(label),
compute_pass,
command_encoder: Dom::from_ref(parent),
}
}
pub(crate) fn new(
global: &GlobalScope,
channel: WebGPU,
parent: &GPUCommandEncoder,
compute_pass: WebGPUComputePass,
label: USVString,
can_gc: CanGc,
) -> DomRoot<Self> {
reflect_dom_object(
Box::new(GPUComputePassEncoder::new_inherited(
channel,
parent,
compute_pass,
label,
)),
global,
can_gc,
)
}
}
impl GPUComputePassEncoderMethods<crate::DomTypeHolder> for GPUComputePassEncoder {
/// <https://gpuweb.github.io/gpuweb/#dom-gpuobjectbase-label>
fn Label(&self) -> USVString {
self.label.borrow().clone()
}
/// <https://gpuweb.github.io/gpuweb/#dom-gpuobjectbase-label>
fn SetLabel(&self, value: USVString) {
*self.label.borrow_mut() = value;
}
/// <https://gpuweb.github.io/gpuweb/#dom-gpucomputepassencoder-dispatchworkgroups>
fn DispatchWorkgroups(&self, x: u32, y: u32, z: u32) {
if let Err(e) = self
.channel
.0
.send(WebGPURequest::ComputePassDispatchWorkgroups {
compute_pass_id: self.compute_pass.0,
x,
y,
z,
device_id: self.command_encoder.device_id().0,
})
{
warn!("Error sending WebGPURequest::ComputePassDispatchWorkgroups: {e:?}")
}
}
/// <https://gpuweb.github.io/gpuweb/#dom-gpucomputepassencoder-dispatchworkgroupsindirect>
fn DispatchWorkgroupsIndirect(&self, buffer: &GPUBuffer, offset: u64) {
if let Err(e) = self
.channel
.0
.send(WebGPURequest::ComputePassDispatchWorkgroupsIndirect {
compute_pass_id: self.compute_pass.0,
buffer_id: buffer.id().0,
offset,
device_id: self.command_encoder.device_id().0,
})
{
warn!("Error sending WebGPURequest::ComputePassDispatchWorkgroupsIndirect: {e:?}")
}
}
/// <https://gpuweb.github.io/gpuweb/#dom-gpurenderpassencoder-endpass>
fn End(&self) {
if let Err(e) = self.channel.0.send(WebGPURequest::EndComputePass {
compute_pass_id: self.compute_pass.0,
device_id: self.command_encoder.device_id().0,
command_encoder_id: self.command_encoder.id().0,
}) {
warn!("Failed to send WebGPURequest::EndComputePass: {e:?}");
}
}
/// <https://gpuweb.github.io/gpuweb/#dom-gpuprogrammablepassencoder-setbindgroup>
fn SetBindGroup(&self, index: u32, bind_group: &GPUBindGroup, offsets: Vec<u32>) {
if let Err(e) = self.channel.0.send(WebGPURequest::ComputePassSetBindGroup {
compute_pass_id: self.compute_pass.0,
index,
bind_group_id: bind_group.id().0,
offsets,
device_id: self.command_encoder.device_id().0,
}) {
warn!("Error sending WebGPURequest::ComputePassSetBindGroup: {e:?}")
}
}
/// <https://gpuweb.github.io/gpuweb/#dom-gpucomputepassencoder-setpipeline>
fn SetPipeline(&self, pipeline: &GPUComputePipeline) {
if let Err(e) = self.channel.0.send(WebGPURequest::ComputePassSetPipeline {
compute_pass_id: self.compute_pass.0,
pipeline_id: pipeline.id().0,
device_id: self.command_encoder.device_id().0,
}) {
warn!("Error sending WebGPURequest::ComputePassSetPipeline: {e:?}")
}
}
}
impl Drop for GPUComputePassEncoder {
fn drop(&mut self) {
if let Err(e) = self
.channel
.0
.send(WebGPURequest::DropComputePass(self.compute_pass.0))
{
warn!("Failed to send WebGPURequest::DropComputePass with {e:?}");
}
let reflector = script_bindings::reflector::DomObject::reflector(self);
reflector.drop_memory(self);
}
}