Skip to content

Commit 63f3df8

Browse files
committed
[wgpu-core] split command encoders from command buffers
1 parent 83badd5 commit 63f3df8

23 files changed

Lines changed: 245 additions & 236 deletions

File tree

deno_webgpu/command_encoder.rs

Lines changed: 5 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
use std::borrow::Cow;
44
use std::cell::RefCell;
5-
use std::sync::atomic::{AtomicBool, Ordering};
65

76
use deno_core::cppgc::Ptr;
87
use deno_core::op2;
@@ -29,19 +28,11 @@ pub struct GPUCommandEncoder {
2928

3029
pub id: wgpu_core::id::CommandEncoderId,
3130
pub label: String,
32-
33-
pub finished: AtomicBool,
3431
}
3532

3633
impl Drop for GPUCommandEncoder {
3734
fn drop(&mut self) {
38-
// Command encoders and command buffers are both the same wgpu object.
39-
// At the time `finished` is set, ownership of the id (and
40-
// responsibility for dropping it) transfers from the encoder to the
41-
// buffer.
42-
if !self.finished.load(Ordering::SeqCst) {
43-
self.instance.command_encoder_drop(self.id);
44-
}
35+
self.instance.command_encoder_drop(self.id);
4536
}
4637
}
4738

@@ -416,34 +407,22 @@ impl GPUCommandEncoder {
416407
fn finish(
417408
&self,
418409
#[webidl] descriptor: crate::command_buffer::GPUCommandBufferDescriptor,
419-
) -> Result<GPUCommandBuffer, JsErrorBox> {
410+
) -> GPUCommandBuffer {
420411
let wgpu_descriptor = wgpu_types::CommandBufferDescriptor {
421412
label: crate::transform_label(descriptor.label.clone()),
422413
};
423414

424-
// TODO(https://github.com/gfx-rs/wgpu/issues/7812): This is not right,
425-
// it should be a validation error, and it would be nice if we can just
426-
// let wgpu generate it for us. The problem is that if the encoder was
427-
// already finished, we transferred ownership of the id to a command
428-
// buffer, so we have to bail out before we mint a duplicate command
429-
// buffer with the same id below.
430-
if self.finished.fetch_or(true, Ordering::SeqCst) {
431-
return Err(JsErrorBox::type_error(
432-
"The command encoder has already finished.",
433-
));
434-
}
435-
436415
let (id, err) = self
437416
.instance
438-
.command_encoder_finish(self.id, &wgpu_descriptor);
417+
.command_encoder_finish(self.id, &wgpu_descriptor, None);
439418

440419
self.error_handler.push_error(err);
441420

442-
Ok(GPUCommandBuffer {
421+
GPUCommandBuffer {
443422
instance: self.instance.clone(),
444423
id,
445424
label: descriptor.label,
446-
})
425+
}
447426
}
448427

449428
fn push_debug_group(&self, #[webidl] group_label: String) {

deno_webgpu/device.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -498,7 +498,6 @@ impl GPUDevice {
498498
error_handler: self.error_handler.clone(),
499499
id,
500500
label,
501-
finished: Default::default(),
502501
}
503502
}
504503

player/src/bin/play.rs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ fn main() {
77

88
use player::GlobalPlay as _;
99
use wgc::device::trace;
10+
use wgpu_core::identity::IdentityManager;
1011

1112
use std::{
1213
fs,
@@ -52,7 +53,8 @@ fn main() {
5253
.unwrap();
5354

5455
let global = wgc::global::Global::new("player", &wgt::InstanceDescriptor::default());
55-
let mut command_buffer_id_manager = wgc::identity::IdentityManager::new();
56+
let mut command_encoder_id_manager = IdentityManager::new();
57+
let mut command_buffer_id_manager = IdentityManager::new();
5658

5759
#[cfg(feature = "winit")]
5860
let surface = unsafe {
@@ -102,7 +104,14 @@ fn main() {
102104
unsafe { global.device_start_graphics_debugger_capture(device) };
103105

104106
while let Some(action) = actions.pop() {
105-
global.process(device, queue, action, &dir, &mut command_buffer_id_manager);
107+
global.process(
108+
device,
109+
queue,
110+
action,
111+
&dir,
112+
&mut command_encoder_id_manager,
113+
&mut command_buffer_id_manager,
114+
);
106115
}
107116

108117
unsafe { global.device_stop_graphics_debugger_capture(device) };
@@ -164,6 +173,7 @@ fn main() {
164173
queue,
165174
action,
166175
&dir,
176+
&mut command_encoder_id_manager,
167177
&mut command_buffer_id_manager,
168178
);
169179
}

player/src/lib.rs

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
extern crate wgpu_core as wgc;
77
extern crate wgpu_types as wgt;
88

9-
use wgc::device::trace;
9+
use wgc::{device::trace, identity::IdentityManager};
1010

1111
use std::{borrow::Cow, fs, path::Path};
1212

@@ -15,14 +15,16 @@ pub trait GlobalPlay {
1515
&self,
1616
encoder: wgc::id::CommandEncoderId,
1717
commands: Vec<trace::Command>,
18+
command_buffer_id_manager: &mut IdentityManager<wgc::id::markers::CommandBuffer>,
1819
) -> wgc::id::CommandBufferId;
1920
fn process(
2021
&self,
2122
device: wgc::id::DeviceId,
2223
queue: wgc::id::QueueId,
2324
action: trace::Action,
2425
dir: &Path,
25-
comb_manager: &mut wgc::identity::IdentityManager<wgc::id::markers::CommandBuffer>,
26+
command_encoder_id_manager: &mut IdentityManager<wgc::id::markers::CommandEncoder>,
27+
command_buffer_id_manager: &mut IdentityManager<wgc::id::markers::CommandBuffer>,
2628
);
2729
}
2830

@@ -31,6 +33,7 @@ impl GlobalPlay for wgc::global::Global {
3133
&self,
3234
encoder: wgc::id::CommandEncoderId,
3335
commands: Vec<trace::Command>,
36+
command_buffer_id_manager: &mut IdentityManager<wgc::id::markers::CommandBuffer>,
3437
) -> wgc::id::CommandBufferId {
3538
for command in commands {
3639
match command {
@@ -172,8 +175,11 @@ impl GlobalPlay for wgc::global::Global {
172175
}
173176
}
174177
}
175-
let (cmd_buf, error) =
176-
self.command_encoder_finish(encoder, &wgt::CommandBufferDescriptor { label: None });
178+
let (cmd_buf, error) = self.command_encoder_finish(
179+
encoder,
180+
&wgt::CommandBufferDescriptor { label: None },
181+
Some(command_buffer_id_manager.process()),
182+
);
177183
if let Some(e) = error {
178184
panic!("{e}");
179185
}
@@ -186,7 +192,8 @@ impl GlobalPlay for wgc::global::Global {
186192
queue: wgc::id::QueueId,
187193
action: trace::Action,
188194
dir: &Path,
189-
comb_manager: &mut wgc::identity::IdentityManager<wgc::id::markers::CommandBuffer>,
195+
command_encoder_id_manager: &mut IdentityManager<wgc::id::markers::CommandEncoder>,
196+
command_buffer_id_manager: &mut IdentityManager<wgc::id::markers::CommandBuffer>,
190197
) {
191198
use wgc::device::trace::Action;
192199
log::debug!("action {action:?}");
@@ -379,12 +386,12 @@ impl GlobalPlay for wgc::global::Global {
379386
let (encoder, error) = self.device_create_command_encoder(
380387
device,
381388
&wgt::CommandEncoderDescriptor { label: None },
382-
Some(comb_manager.process().into_command_encoder_id()),
389+
Some(command_encoder_id_manager.process()),
383390
);
384391
if let Some(e) = error {
385392
panic!("{e}");
386393
}
387-
let cmdbuf = self.encode_commands(encoder, commands);
394+
let cmdbuf = self.encode_commands(encoder, commands, command_buffer_id_manager);
388395
self.queue_submit(queue, &[cmdbuf]).unwrap();
389396
}
390397
Action::CreateBlas { id, desc, sizes } => {

player/tests/player/main.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ use std::{
2020
path::{Path, PathBuf},
2121
slice,
2222
};
23+
use wgc::identity::IdentityManager;
2324

2425
#[derive(serde::Deserialize)]
2526
struct RawId {
@@ -104,14 +105,16 @@ impl Test<'_> {
104105
panic!("{e:?}");
105106
}
106107

107-
let mut command_buffer_id_manager = wgc::identity::IdentityManager::new();
108+
let mut command_encoder_id_manager = IdentityManager::new();
109+
let mut command_buffer_id_manager = IdentityManager::new();
108110
println!("\t\t\tRunning...");
109111
for action in self.actions {
110112
global.process(
111113
device_id,
112114
queue_id,
113115
action,
114116
dir,
117+
&mut command_encoder_id_manager,
115118
&mut command_buffer_id_manager,
116119
);
117120
}

tests/tests/wgpu-gpu/mem_leaks.rs

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ async fn draw_test_with_reports(
179179

180180
let global_report = ctx.instance.generate_report().unwrap();
181181
let report = global_report.hub_report();
182-
assert_eq!(report.command_buffers.num_allocated, 1);
182+
assert_eq!(report.command_encoders.num_allocated, 1);
183183
assert_eq!(report.buffers.num_allocated, 1);
184184

185185
let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
@@ -206,7 +206,7 @@ async fn draw_test_with_reports(
206206
assert_eq!(report.pipeline_layouts.num_allocated, 1);
207207
assert_eq!(report.render_pipelines.num_allocated, 1);
208208
assert_eq!(report.compute_pipelines.num_allocated, 0);
209-
assert_eq!(report.command_buffers.num_allocated, 1);
209+
assert_eq!(report.command_encoders.num_allocated, 1);
210210
assert_eq!(report.render_bundles.num_allocated, 0);
211211
assert_eq!(report.texture_views.num_allocated, 1);
212212
assert_eq!(report.textures.num_allocated, 1);
@@ -223,15 +223,15 @@ async fn draw_test_with_reports(
223223

224224
let global_report = ctx.instance.generate_report().unwrap();
225225
let report = global_report.hub_report();
226-
assert_eq!(report.command_buffers.num_kept_from_user, 1);
226+
assert_eq!(report.command_encoders.num_kept_from_user, 1);
227227
assert_eq!(report.render_pipelines.num_kept_from_user, 0);
228228
assert_eq!(report.pipeline_layouts.num_kept_from_user, 0);
229229
assert_eq!(report.bind_group_layouts.num_kept_from_user, 0);
230230
assert_eq!(report.bind_groups.num_kept_from_user, 0);
231231
assert_eq!(report.buffers.num_kept_from_user, 0);
232232
assert_eq!(report.texture_views.num_kept_from_user, 0);
233233
assert_eq!(report.textures.num_kept_from_user, 0);
234-
assert_eq!(report.command_buffers.num_allocated, 1);
234+
assert_eq!(report.command_encoders.num_allocated, 1);
235235
assert_eq!(report.render_pipelines.num_allocated, 0);
236236
assert_eq!(report.pipeline_layouts.num_allocated, 0);
237237
assert_eq!(report.bind_group_layouts.num_allocated, 0);
@@ -240,12 +240,18 @@ async fn draw_test_with_reports(
240240
assert_eq!(report.texture_views.num_allocated, 0);
241241
assert_eq!(report.textures.num_allocated, 0);
242242

243-
let submit_index = ctx.queue.submit(Some(encoder.finish()));
243+
let command_buffer = encoder.finish();
244+
245+
let global_report = ctx.instance.generate_report().unwrap();
246+
let report = global_report.hub_report();
247+
assert_eq!(report.command_encoders.num_allocated, 0);
248+
assert_eq!(report.command_buffers.num_allocated, 1);
249+
250+
let submit_index = ctx.queue.submit(Some(command_buffer));
244251

245-
// TODO: fix in https://github.com/gfx-rs/wgpu/pull/5141
246-
// let global_report = ctx.instance.generate_report().unwrap();
247-
// let report = global_report.hub_report();
248-
// assert_eq!(report.command_buffers.num_allocated, 0);
252+
let global_report = ctx.instance.generate_report().unwrap();
253+
let report = global_report.hub_report();
254+
assert_eq!(report.command_buffers.num_allocated, 0);
249255

250256
ctx.async_poll(wgpu::PollType::wait_for(submit_index))
251257
.await

wgpu-core/src/as_hal.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -346,7 +346,7 @@ impl Global {
346346

347347
let hub = &self.hub;
348348

349-
let cmd_buf = hub.command_buffers.get(id.into_command_buffer_id());
349+
let cmd_buf = hub.command_encoders.get(id);
350350
let mut cmd_buf_data = cmd_buf.data.lock();
351351
cmd_buf_data.record_as_hal_mut(|opt_cmd_buf| -> R {
352352
hal_command_encoder_callback(opt_cmd_buf.and_then(|cmd_buf| {

wgpu-core/src/command/clear.rs

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use crate::device::trace::Command as TraceCommand;
66
use crate::{
77
api_log,
88
command::EncoderStateError,
9-
device::DeviceError,
9+
device::{DeviceError, MissingFeatures},
1010
get_lowest_common_denom,
1111
global::Global,
1212
id::{BufferId, CommandEncoderId, TextureId},
@@ -30,10 +30,10 @@ use wgt::{
3030
#[derive(Clone, Debug, Error)]
3131
#[non_exhaustive]
3232
pub enum ClearError {
33-
#[error("To use clear_texture the CLEAR_TEXTURE feature needs to be enabled")]
34-
MissingClearTextureFeature,
3533
#[error(transparent)]
3634
DestroyedResource(#[from] DestroyedResourceError),
35+
#[error(transparent)]
36+
MissingFeatures(#[from] MissingFeatures),
3737
#[error("{0} can not be cleared")]
3838
NoValidTextureClearMode(ResourceErrorIdent),
3939
#[error("Buffer clear size {0:?} is not a multiple of `COPY_BUFFER_ALIGNMENT`")]
@@ -84,12 +84,12 @@ impl WebGpuError for ClearError {
8484
fn webgpu_error_type(&self) -> ErrorType {
8585
let e: &dyn WebGpuError = match self {
8686
Self::DestroyedResource(e) => e,
87+
Self::MissingFeatures(e) => e,
8788
Self::MissingBufferUsage(e) => e,
8889
Self::Device(e) => e,
8990
Self::EncoderState(e) => e,
9091
Self::InvalidResource(e) => e,
9192
Self::NoValidTextureClearMode(..)
92-
| Self::MissingClearTextureFeature
9393
| Self::UnalignedFillSize(..)
9494
| Self::UnalignedBufferOffset(..)
9595
| Self::OffsetPlusSizeExceeds64BitBounds { .. }
@@ -115,9 +115,7 @@ impl Global {
115115

116116
let hub = &self.hub;
117117

118-
let cmd_buf = hub
119-
.command_buffers
120-
.get(command_encoder_id.into_command_buffer_id());
118+
let cmd_buf = hub.command_encoders.get(command_encoder_id);
121119
let mut cmd_buf_data = cmd_buf.data.lock();
122120
cmd_buf_data.record_with(|cmd_buf_data| -> Result<(), ClearError> {
123121
#[cfg(feature = "trace")]
@@ -202,9 +200,7 @@ impl Global {
202200

203201
let hub = &self.hub;
204202

205-
let cmd_buf = hub
206-
.command_buffers
207-
.get(command_encoder_id.into_command_buffer_id());
203+
let cmd_buf = hub.command_encoders.get(command_encoder_id);
208204
let mut cmd_buf_data = cmd_buf.data.lock();
209205
cmd_buf_data.record_with(|cmd_buf_data| -> Result<(), ClearError> {
210206
#[cfg(feature = "trace")]
@@ -217,9 +213,9 @@ impl Global {
217213

218214
cmd_buf.device.check_is_valid()?;
219215

220-
if !cmd_buf.support_clear_texture {
221-
return Err(ClearError::MissingClearTextureFeature);
222-
}
216+
cmd_buf
217+
.device
218+
.require_features(wgt::Features::CLEAR_TEXTURE)?;
223219

224220
let dst_texture = hub.textures.get(dst).get()?;
225221

0 commit comments

Comments
 (0)