[deno] Fix dropping of command encoders/buffers, and an enum typo (#7808)

Fixes #7797
This commit is contained in:
Andy Leiserson
2025-06-16 10:50:19 -07:00
committed by GitHub
parent 371c8fd1db
commit afa0f71736
6 changed files with 35 additions and 24 deletions

View File

@@ -9,6 +9,11 @@ webgpu:api,operation,compute,basic:memcpy:*
//FAIL: webgpu:api,operation,compute,basic:large_dispatch:*
webgpu:api,operation,compute_pipeline,overrides:*
webgpu:api,operation,device,lost:*
webgpu:api,validation,queue,submit:command_buffer,device_mismatch:*
webgpu:api,validation,queue,submit:command_buffer,duplicate_buffers:*
webgpu:api,validation,queue,submit:command_buffer,submit_invalidates:*
//FAIL: webgpu:api,validation,queue,submit:command_buffer,invalid_submit_invalidates:*
// https://github.com/gfx-rs/wgpu/issues/3911#issuecomment-2972995675
webgpu:api,operation,render_pipeline,overrides:*
webgpu:api,operation,rendering,basic:clear:*
webgpu:api,operation,rendering,basic:fullscreen_quad:*

View File

@@ -1,7 +1,5 @@
// Copyright 2018-2025 the Deno authors. MIT license.
use std::cell::OnceCell;
use deno_core::op2;
use deno_core::GarbageCollected;
use deno_core::WebIDL;
@@ -12,15 +10,11 @@ pub struct GPUCommandBuffer {
pub instance: Instance,
pub id: wgpu_core::id::CommandBufferId,
pub label: String,
pub consumed: OnceCell<()>,
}
impl Drop for GPUCommandBuffer {
fn drop(&mut self) {
if self.consumed.get().is_none() {
self.instance.command_buffer_drop(self.id);
}
self.instance.command_buffer_drop(self.id);
}
}

View File

@@ -2,6 +2,7 @@
use std::borrow::Cow;
use std::cell::RefCell;
use std::sync::atomic::{AtomicBool, Ordering};
use deno_core::cppgc::Ptr;
use deno_core::op2;
@@ -28,11 +29,19 @@ pub struct GPUCommandEncoder {
pub id: wgpu_core::id::CommandEncoderId,
pub label: String,
pub finished: AtomicBool,
}
impl Drop for GPUCommandEncoder {
fn drop(&mut self) {
self.instance.command_encoder_drop(self.id);
// Command encoders and command buffers are both the same wgpu object.
// At the time `finished` is set, ownership of the id (and
// responsibility for dropping it) transfers from the encoder to the
// buffer.
if !self.finished.load(Ordering::SeqCst) {
self.instance.command_encoder_drop(self.id);
}
}
}
@@ -407,23 +416,34 @@ impl GPUCommandEncoder {
fn finish(
&self,
#[webidl] descriptor: crate::command_buffer::GPUCommandBufferDescriptor,
) -> GPUCommandBuffer {
) -> Result<GPUCommandBuffer, JsErrorBox> {
let wgpu_descriptor = wgpu_types::CommandBufferDescriptor {
label: crate::transform_label(descriptor.label.clone()),
};
// TODO(https://github.com/gfx-rs/wgpu/issues/7812): This is not right,
// it should be a validation error, and it would be nice if we can just
// let wgpu generate it for us. The problem is that if the encoder was
// already finished, we transferred ownership of the id to a command
// buffer, so we have to bail out before we mint a duplicate command
// buffer with the same id below.
if self.finished.fetch_or(true, Ordering::SeqCst) {
return Err(JsErrorBox::type_error(
"The command encoder has already finished.",
));
}
let (id, err) = self
.instance
.command_encoder_finish(self.id, &wgpu_descriptor);
self.error_handler.push_error(err);
GPUCommandBuffer {
Ok(GPUCommandBuffer {
instance: self.instance.clone(),
id,
label: descriptor.label,
consumed: Default::default(),
}
})
}
fn push_debug_group(&self, #[webidl] group_label: String) {

View File

@@ -498,6 +498,7 @@ impl GPUDevice {
error_handler: self.error_handler.clone(),
id,
label,
finished: Default::default(),
}
}

View File

@@ -59,17 +59,8 @@ impl GPUQueue {
) -> Result<v8::Local<v8::Value>, JsErrorBox> {
let ids = command_buffers
.into_iter()
.enumerate()
.map(|(i, cb)| {
if cb.consumed.set(()).is_err() {
Err(JsErrorBox::type_error(format!(
"The command buffer at position {i} has already been submitted."
)))
} else {
Ok(cb.id)
}
})
.collect::<Result<Vec<_>, _>>()?;
.map(|cb| cb.id)
.collect::<Vec<_>>();
let err = self.instance.queue_submit(self.id, &ids).err();

View File

@@ -550,7 +550,7 @@ impl From<GPUTextureFormat> for TextureFormat {
channel: AstcChannel::Unorm,
},
GPUTextureFormat::Astc4x4UnormSrgb => Self::Astc {
block: AstcBlock::B5x4,
block: AstcBlock::B4x4,
channel: AstcChannel::UnormSrgb,
},
GPUTextureFormat::Astc5x4Unorm => Self::Astc {