[wgpu-core] split command encoders from command buffers

This commit is contained in:
teoxoy 2025-07-18 19:48:20 +02:00 committed by Teodor Tanasoaia
parent 83badd52ab
commit 63f3df86c8
23 changed files with 245 additions and 236 deletions

View File

@ -2,7 +2,6 @@
use std::borrow::Cow; use std::borrow::Cow;
use std::cell::RefCell; use std::cell::RefCell;
use std::sync::atomic::{AtomicBool, Ordering};
use deno_core::cppgc::Ptr; use deno_core::cppgc::Ptr;
use deno_core::op2; use deno_core::op2;
@ -29,19 +28,11 @@ pub struct GPUCommandEncoder {
pub id: wgpu_core::id::CommandEncoderId, pub id: wgpu_core::id::CommandEncoderId,
pub label: String, pub label: String,
pub finished: AtomicBool,
} }
impl Drop for GPUCommandEncoder { impl Drop for GPUCommandEncoder {
fn drop(&mut self) { fn drop(&mut self) {
// Command encoders and command buffers are both the same wgpu object. self.instance.command_encoder_drop(self.id);
// 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);
}
} }
} }
@ -416,34 +407,22 @@ impl GPUCommandEncoder {
fn finish( fn finish(
&self, &self,
#[webidl] descriptor: crate::command_buffer::GPUCommandBufferDescriptor, #[webidl] descriptor: crate::command_buffer::GPUCommandBufferDescriptor,
) -> Result<GPUCommandBuffer, JsErrorBox> { ) -> GPUCommandBuffer {
let wgpu_descriptor = wgpu_types::CommandBufferDescriptor { let wgpu_descriptor = wgpu_types::CommandBufferDescriptor {
label: crate::transform_label(descriptor.label.clone()), 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 let (id, err) = self
.instance .instance
.command_encoder_finish(self.id, &wgpu_descriptor); .command_encoder_finish(self.id, &wgpu_descriptor, None);
self.error_handler.push_error(err); self.error_handler.push_error(err);
Ok(GPUCommandBuffer { GPUCommandBuffer {
instance: self.instance.clone(), instance: self.instance.clone(),
id, id,
label: descriptor.label, label: descriptor.label,
}) }
} }
fn push_debug_group(&self, #[webidl] group_label: String) { fn push_debug_group(&self, #[webidl] group_label: String) {

View File

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

View File

@ -7,6 +7,7 @@ fn main() {
use player::GlobalPlay as _; use player::GlobalPlay as _;
use wgc::device::trace; use wgc::device::trace;
use wgpu_core::identity::IdentityManager;
use std::{ use std::{
fs, fs,
@ -52,7 +53,8 @@ fn main() {
.unwrap(); .unwrap();
let global = wgc::global::Global::new("player", &wgt::InstanceDescriptor::default()); let global = wgc::global::Global::new("player", &wgt::InstanceDescriptor::default());
let mut command_buffer_id_manager = wgc::identity::IdentityManager::new(); let mut command_encoder_id_manager = IdentityManager::new();
let mut command_buffer_id_manager = IdentityManager::new();
#[cfg(feature = "winit")] #[cfg(feature = "winit")]
let surface = unsafe { let surface = unsafe {
@ -102,7 +104,14 @@ fn main() {
unsafe { global.device_start_graphics_debugger_capture(device) }; unsafe { global.device_start_graphics_debugger_capture(device) };
while let Some(action) = actions.pop() { while let Some(action) = actions.pop() {
global.process(device, queue, action, &dir, &mut command_buffer_id_manager); global.process(
device,
queue,
action,
&dir,
&mut command_encoder_id_manager,
&mut command_buffer_id_manager,
);
} }
unsafe { global.device_stop_graphics_debugger_capture(device) }; unsafe { global.device_stop_graphics_debugger_capture(device) };
@ -164,6 +173,7 @@ fn main() {
queue, queue,
action, action,
&dir, &dir,
&mut command_encoder_id_manager,
&mut command_buffer_id_manager, &mut command_buffer_id_manager,
); );
} }

View File

@ -6,7 +6,7 @@
extern crate wgpu_core as wgc; extern crate wgpu_core as wgc;
extern crate wgpu_types as wgt; extern crate wgpu_types as wgt;
use wgc::device::trace; use wgc::{device::trace, identity::IdentityManager};
use std::{borrow::Cow, fs, path::Path}; use std::{borrow::Cow, fs, path::Path};
@ -15,6 +15,7 @@ pub trait GlobalPlay {
&self, &self,
encoder: wgc::id::CommandEncoderId, encoder: wgc::id::CommandEncoderId,
commands: Vec<trace::Command>, commands: Vec<trace::Command>,
command_buffer_id_manager: &mut IdentityManager<wgc::id::markers::CommandBuffer>,
) -> wgc::id::CommandBufferId; ) -> wgc::id::CommandBufferId;
fn process( fn process(
&self, &self,
@ -22,7 +23,8 @@ pub trait GlobalPlay {
queue: wgc::id::QueueId, queue: wgc::id::QueueId,
action: trace::Action, action: trace::Action,
dir: &Path, dir: &Path,
comb_manager: &mut wgc::identity::IdentityManager<wgc::id::markers::CommandBuffer>, command_encoder_id_manager: &mut IdentityManager<wgc::id::markers::CommandEncoder>,
command_buffer_id_manager: &mut IdentityManager<wgc::id::markers::CommandBuffer>,
); );
} }
@ -31,6 +33,7 @@ impl GlobalPlay for wgc::global::Global {
&self, &self,
encoder: wgc::id::CommandEncoderId, encoder: wgc::id::CommandEncoderId,
commands: Vec<trace::Command>, commands: Vec<trace::Command>,
command_buffer_id_manager: &mut IdentityManager<wgc::id::markers::CommandBuffer>,
) -> wgc::id::CommandBufferId { ) -> wgc::id::CommandBufferId {
for command in commands { for command in commands {
match command { match command {
@ -172,8 +175,11 @@ impl GlobalPlay for wgc::global::Global {
} }
} }
} }
let (cmd_buf, error) = let (cmd_buf, error) = self.command_encoder_finish(
self.command_encoder_finish(encoder, &wgt::CommandBufferDescriptor { label: None }); encoder,
&wgt::CommandBufferDescriptor { label: None },
Some(command_buffer_id_manager.process()),
);
if let Some(e) = error { if let Some(e) = error {
panic!("{e}"); panic!("{e}");
} }
@ -186,7 +192,8 @@ impl GlobalPlay for wgc::global::Global {
queue: wgc::id::QueueId, queue: wgc::id::QueueId,
action: trace::Action, action: trace::Action,
dir: &Path, dir: &Path,
comb_manager: &mut wgc::identity::IdentityManager<wgc::id::markers::CommandBuffer>, command_encoder_id_manager: &mut IdentityManager<wgc::id::markers::CommandEncoder>,
command_buffer_id_manager: &mut IdentityManager<wgc::id::markers::CommandBuffer>,
) { ) {
use wgc::device::trace::Action; use wgc::device::trace::Action;
log::debug!("action {action:?}"); log::debug!("action {action:?}");
@ -379,12 +386,12 @@ impl GlobalPlay for wgc::global::Global {
let (encoder, error) = self.device_create_command_encoder( let (encoder, error) = self.device_create_command_encoder(
device, device,
&wgt::CommandEncoderDescriptor { label: None }, &wgt::CommandEncoderDescriptor { label: None },
Some(comb_manager.process().into_command_encoder_id()), Some(command_encoder_id_manager.process()),
); );
if let Some(e) = error { if let Some(e) = error {
panic!("{e}"); panic!("{e}");
} }
let cmdbuf = self.encode_commands(encoder, commands); let cmdbuf = self.encode_commands(encoder, commands, command_buffer_id_manager);
self.queue_submit(queue, &[cmdbuf]).unwrap(); self.queue_submit(queue, &[cmdbuf]).unwrap();
} }
Action::CreateBlas { id, desc, sizes } => { Action::CreateBlas { id, desc, sizes } => {

View File

@ -20,6 +20,7 @@ use std::{
path::{Path, PathBuf}, path::{Path, PathBuf},
slice, slice,
}; };
use wgc::identity::IdentityManager;
#[derive(serde::Deserialize)] #[derive(serde::Deserialize)]
struct RawId { struct RawId {
@ -104,7 +105,8 @@ impl Test<'_> {
panic!("{e:?}"); panic!("{e:?}");
} }
let mut command_buffer_id_manager = wgc::identity::IdentityManager::new(); let mut command_encoder_id_manager = IdentityManager::new();
let mut command_buffer_id_manager = IdentityManager::new();
println!("\t\t\tRunning..."); println!("\t\t\tRunning...");
for action in self.actions { for action in self.actions {
global.process( global.process(
@ -112,6 +114,7 @@ impl Test<'_> {
queue_id, queue_id,
action, action,
dir, dir,
&mut command_encoder_id_manager,
&mut command_buffer_id_manager, &mut command_buffer_id_manager,
); );
} }

View File

@ -179,7 +179,7 @@ async fn draw_test_with_reports(
let global_report = ctx.instance.generate_report().unwrap(); let global_report = ctx.instance.generate_report().unwrap();
let report = global_report.hub_report(); let report = global_report.hub_report();
assert_eq!(report.command_buffers.num_allocated, 1); assert_eq!(report.command_encoders.num_allocated, 1);
assert_eq!(report.buffers.num_allocated, 1); assert_eq!(report.buffers.num_allocated, 1);
let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
@ -206,7 +206,7 @@ async fn draw_test_with_reports(
assert_eq!(report.pipeline_layouts.num_allocated, 1); assert_eq!(report.pipeline_layouts.num_allocated, 1);
assert_eq!(report.render_pipelines.num_allocated, 1); assert_eq!(report.render_pipelines.num_allocated, 1);
assert_eq!(report.compute_pipelines.num_allocated, 0); assert_eq!(report.compute_pipelines.num_allocated, 0);
assert_eq!(report.command_buffers.num_allocated, 1); assert_eq!(report.command_encoders.num_allocated, 1);
assert_eq!(report.render_bundles.num_allocated, 0); assert_eq!(report.render_bundles.num_allocated, 0);
assert_eq!(report.texture_views.num_allocated, 1); assert_eq!(report.texture_views.num_allocated, 1);
assert_eq!(report.textures.num_allocated, 1); assert_eq!(report.textures.num_allocated, 1);
@ -223,7 +223,7 @@ async fn draw_test_with_reports(
let global_report = ctx.instance.generate_report().unwrap(); let global_report = ctx.instance.generate_report().unwrap();
let report = global_report.hub_report(); let report = global_report.hub_report();
assert_eq!(report.command_buffers.num_kept_from_user, 1); assert_eq!(report.command_encoders.num_kept_from_user, 1);
assert_eq!(report.render_pipelines.num_kept_from_user, 0); assert_eq!(report.render_pipelines.num_kept_from_user, 0);
assert_eq!(report.pipeline_layouts.num_kept_from_user, 0); assert_eq!(report.pipeline_layouts.num_kept_from_user, 0);
assert_eq!(report.bind_group_layouts.num_kept_from_user, 0); assert_eq!(report.bind_group_layouts.num_kept_from_user, 0);
@ -231,7 +231,7 @@ async fn draw_test_with_reports(
assert_eq!(report.buffers.num_kept_from_user, 0); assert_eq!(report.buffers.num_kept_from_user, 0);
assert_eq!(report.texture_views.num_kept_from_user, 0); assert_eq!(report.texture_views.num_kept_from_user, 0);
assert_eq!(report.textures.num_kept_from_user, 0); assert_eq!(report.textures.num_kept_from_user, 0);
assert_eq!(report.command_buffers.num_allocated, 1); assert_eq!(report.command_encoders.num_allocated, 1);
assert_eq!(report.render_pipelines.num_allocated, 0); assert_eq!(report.render_pipelines.num_allocated, 0);
assert_eq!(report.pipeline_layouts.num_allocated, 0); assert_eq!(report.pipeline_layouts.num_allocated, 0);
assert_eq!(report.bind_group_layouts.num_allocated, 0); assert_eq!(report.bind_group_layouts.num_allocated, 0);
@ -240,12 +240,18 @@ async fn draw_test_with_reports(
assert_eq!(report.texture_views.num_allocated, 0); assert_eq!(report.texture_views.num_allocated, 0);
assert_eq!(report.textures.num_allocated, 0); assert_eq!(report.textures.num_allocated, 0);
let submit_index = ctx.queue.submit(Some(encoder.finish())); let command_buffer = encoder.finish();
// TODO: fix in https://github.com/gfx-rs/wgpu/pull/5141 let global_report = ctx.instance.generate_report().unwrap();
// let global_report = ctx.instance.generate_report().unwrap(); let report = global_report.hub_report();
// let report = global_report.hub_report(); assert_eq!(report.command_encoders.num_allocated, 0);
// assert_eq!(report.command_buffers.num_allocated, 0); assert_eq!(report.command_buffers.num_allocated, 1);
let submit_index = ctx.queue.submit(Some(command_buffer));
let global_report = ctx.instance.generate_report().unwrap();
let report = global_report.hub_report();
assert_eq!(report.command_buffers.num_allocated, 0);
ctx.async_poll(wgpu::PollType::wait_for(submit_index)) ctx.async_poll(wgpu::PollType::wait_for(submit_index))
.await .await

View File

@ -346,7 +346,7 @@ impl Global {
let hub = &self.hub; let hub = &self.hub;
let cmd_buf = hub.command_buffers.get(id.into_command_buffer_id()); let cmd_buf = hub.command_encoders.get(id);
let mut cmd_buf_data = cmd_buf.data.lock(); let mut cmd_buf_data = cmd_buf.data.lock();
cmd_buf_data.record_as_hal_mut(|opt_cmd_buf| -> R { cmd_buf_data.record_as_hal_mut(|opt_cmd_buf| -> R {
hal_command_encoder_callback(opt_cmd_buf.and_then(|cmd_buf| { hal_command_encoder_callback(opt_cmd_buf.and_then(|cmd_buf| {

View File

@ -6,7 +6,7 @@ use crate::device::trace::Command as TraceCommand;
use crate::{ use crate::{
api_log, api_log,
command::EncoderStateError, command::EncoderStateError,
device::DeviceError, device::{DeviceError, MissingFeatures},
get_lowest_common_denom, get_lowest_common_denom,
global::Global, global::Global,
id::{BufferId, CommandEncoderId, TextureId}, id::{BufferId, CommandEncoderId, TextureId},
@ -30,10 +30,10 @@ use wgt::{
#[derive(Clone, Debug, Error)] #[derive(Clone, Debug, Error)]
#[non_exhaustive] #[non_exhaustive]
pub enum ClearError { pub enum ClearError {
#[error("To use clear_texture the CLEAR_TEXTURE feature needs to be enabled")]
MissingClearTextureFeature,
#[error(transparent)] #[error(transparent)]
DestroyedResource(#[from] DestroyedResourceError), DestroyedResource(#[from] DestroyedResourceError),
#[error(transparent)]
MissingFeatures(#[from] MissingFeatures),
#[error("{0} can not be cleared")] #[error("{0} can not be cleared")]
NoValidTextureClearMode(ResourceErrorIdent), NoValidTextureClearMode(ResourceErrorIdent),
#[error("Buffer clear size {0:?} is not a multiple of `COPY_BUFFER_ALIGNMENT`")] #[error("Buffer clear size {0:?} is not a multiple of `COPY_BUFFER_ALIGNMENT`")]
@ -84,12 +84,12 @@ impl WebGpuError for ClearError {
fn webgpu_error_type(&self) -> ErrorType { fn webgpu_error_type(&self) -> ErrorType {
let e: &dyn WebGpuError = match self { let e: &dyn WebGpuError = match self {
Self::DestroyedResource(e) => e, Self::DestroyedResource(e) => e,
Self::MissingFeatures(e) => e,
Self::MissingBufferUsage(e) => e, Self::MissingBufferUsage(e) => e,
Self::Device(e) => e, Self::Device(e) => e,
Self::EncoderState(e) => e, Self::EncoderState(e) => e,
Self::InvalidResource(e) => e, Self::InvalidResource(e) => e,
Self::NoValidTextureClearMode(..) Self::NoValidTextureClearMode(..)
| Self::MissingClearTextureFeature
| Self::UnalignedFillSize(..) | Self::UnalignedFillSize(..)
| Self::UnalignedBufferOffset(..) | Self::UnalignedBufferOffset(..)
| Self::OffsetPlusSizeExceeds64BitBounds { .. } | Self::OffsetPlusSizeExceeds64BitBounds { .. }
@ -115,9 +115,7 @@ impl Global {
let hub = &self.hub; let hub = &self.hub;
let cmd_buf = hub let cmd_buf = hub.command_encoders.get(command_encoder_id);
.command_buffers
.get(command_encoder_id.into_command_buffer_id());
let mut cmd_buf_data = cmd_buf.data.lock(); let mut cmd_buf_data = cmd_buf.data.lock();
cmd_buf_data.record_with(|cmd_buf_data| -> Result<(), ClearError> { cmd_buf_data.record_with(|cmd_buf_data| -> Result<(), ClearError> {
#[cfg(feature = "trace")] #[cfg(feature = "trace")]
@ -202,9 +200,7 @@ impl Global {
let hub = &self.hub; let hub = &self.hub;
let cmd_buf = hub let cmd_buf = hub.command_encoders.get(command_encoder_id);
.command_buffers
.get(command_encoder_id.into_command_buffer_id());
let mut cmd_buf_data = cmd_buf.data.lock(); let mut cmd_buf_data = cmd_buf.data.lock();
cmd_buf_data.record_with(|cmd_buf_data| -> Result<(), ClearError> { cmd_buf_data.record_with(|cmd_buf_data| -> Result<(), ClearError> {
#[cfg(feature = "trace")] #[cfg(feature = "trace")]
@ -217,9 +213,9 @@ impl Global {
cmd_buf.device.check_is_valid()?; cmd_buf.device.check_is_valid()?;
if !cmd_buf.support_clear_texture { cmd_buf
return Err(ClearError::MissingClearTextureFeature); .device
} .require_features(wgt::Features::CLEAR_TEXTURE)?;
let dst_texture = hub.textures.get(dst).get()?; let dst_texture = hub.textures.get(dst).get()?;

View File

@ -7,7 +7,9 @@ use wgt::{
use alloc::{borrow::Cow, boxed::Box, sync::Arc, vec::Vec}; use alloc::{borrow::Cow, boxed::Box, sync::Arc, vec::Vec};
use core::{fmt, str}; use core::{fmt, str};
use crate::command::{pass, EncoderStateError, PassStateError, TimestampWritesError}; use crate::command::{
pass, CommandEncoder, EncoderStateError, PassStateError, TimestampWritesError,
};
use crate::resource::DestroyedResourceError; use crate::resource::DestroyedResourceError;
use crate::{binding_model::BindError, resource::RawResourceAccess}; use crate::{binding_model::BindError, resource::RawResourceAccess};
use crate::{ use crate::{
@ -18,8 +20,8 @@ use crate::{
end_pipeline_statistics_query, end_pipeline_statistics_query,
memory_init::{fixup_discarded_surfaces, SurfacesInDiscardState}, memory_init::{fixup_discarded_surfaces, SurfacesInDiscardState},
pass_base, pass_try, validate_and_begin_pipeline_statistics_query, ArcPassTimestampWrites, pass_base, pass_try, validate_and_begin_pipeline_statistics_query, ArcPassTimestampWrites,
BasePass, BindGroupStateChange, CommandBuffer, CommandEncoderError, MapPassErr, BasePass, BindGroupStateChange, CommandEncoderError, MapPassErr, PassErrorScope,
PassErrorScope, PassTimestampWrites, QueryUseError, StateChange, PassTimestampWrites, QueryUseError, StateChange,
}, },
device::{DeviceError, MissingDownlevelFlags, MissingFeatures}, device::{DeviceError, MissingDownlevelFlags, MissingFeatures},
global::Global, global::Global,
@ -46,12 +48,12 @@ pub struct ComputePass {
/// All pass data & records is stored here. /// All pass data & records is stored here.
base: ComputeBasePass, base: ComputeBasePass,
/// Parent command buffer that this pass records commands into. /// Parent command encoder that this pass records commands into.
/// ///
/// If this is `Some`, then the pass is in WebGPU's "open" state. If it is /// If this is `Some`, then the pass is in WebGPU's "open" state. If it is
/// `None`, then the pass is in the "ended" state. /// `None`, then the pass is in the "ended" state.
/// See <https://www.w3.org/TR/webgpu/#encoder-state> /// See <https://www.w3.org/TR/webgpu/#encoder-state>
parent: Option<Arc<CommandBuffer>>, parent: Option<Arc<CommandEncoder>>,
timestamp_writes: Option<ArcPassTimestampWrites>, timestamp_writes: Option<ArcPassTimestampWrites>,
@ -61,8 +63,8 @@ pub struct ComputePass {
} }
impl ComputePass { impl ComputePass {
/// If the parent command buffer is invalid, the returned pass will be invalid. /// If the parent command encoder is invalid, the returned pass will be invalid.
fn new(parent: Arc<CommandBuffer>, desc: ArcComputePassDescriptor) -> Self { fn new(parent: Arc<CommandEncoder>, desc: ArcComputePassDescriptor) -> Self {
let ArcComputePassDescriptor { let ArcComputePassDescriptor {
label, label,
timestamp_writes, timestamp_writes,
@ -78,7 +80,7 @@ impl ComputePass {
} }
} }
fn new_invalid(parent: Arc<CommandBuffer>, label: &Label, err: ComputePassError) -> Self { fn new_invalid(parent: Arc<CommandEncoder>, label: &Label, err: ComputePassError) -> Self {
Self { Self {
base: BasePass::new_invalid(label, err), base: BasePass::new_invalid(label, err),
parent: Some(parent), parent: Some(parent),
@ -308,7 +310,7 @@ impl<'scope, 'snatch_guard, 'cmd_buf, 'raw_encoder>
); );
} }
CommandBuffer::drain_barriers( CommandEncoder::drain_barriers(
self.general.raw_encoder, self.general.raw_encoder,
&mut self.intermediate_trackers, &mut self.intermediate_trackers,
self.general.snatch_guard, self.general.snatch_guard,
@ -342,7 +344,7 @@ impl Global {
let label = desc.label.as_deref().map(Cow::Borrowed); let label = desc.label.as_deref().map(Cow::Borrowed);
let cmd_buf = hub.command_buffers.get(encoder_id.into_command_buffer_id()); let cmd_buf = hub.command_encoders.get(encoder_id);
let mut cmd_buf_data = cmd_buf.data.lock(); let mut cmd_buf_data = cmd_buf.data.lock();
match cmd_buf_data.lock_encoder() { match cmd_buf_data.lock_encoder() {
@ -433,10 +435,7 @@ impl Global {
) { ) {
#[cfg(feature = "trace")] #[cfg(feature = "trace")]
{ {
let cmd_buf = self let cmd_buf = self.hub.command_encoders.get(encoder_id);
.hub
.command_buffers
.get(encoder_id.into_command_buffer_id());
let mut cmd_buf_data = cmd_buf.data.lock(); let mut cmd_buf_data = cmd_buf.data.lock();
let cmd_buf_data = cmd_buf_data.get_inner(); let cmd_buf_data = cmd_buf_data.get_inner();
@ -750,10 +749,10 @@ impl Global {
.. ..
} = state; } = state;
// Stop the current command buffer. // Stop the current command encoder.
encoder.close().map_pass_err(pass_scope)?; encoder.close().map_pass_err(pass_scope)?;
// Create a new command buffer, which we will insert _before_ the body of the compute pass. // Create a new command encoder, which we will insert _before_ the body of the compute pass.
// //
// Use that buffer to insert barriers and clear discarded images. // Use that buffer to insert barriers and clear discarded images.
let transit = encoder let transit = encoder
@ -766,13 +765,13 @@ impl Global {
device, device,
&snatch_guard, &snatch_guard,
); );
CommandBuffer::insert_barriers_from_tracker( CommandEncoder::insert_barriers_from_tracker(
transit, transit,
tracker, tracker,
&intermediate_trackers, &intermediate_trackers,
&snatch_guard, &snatch_guard,
); );
// Close the command buffer, and swap it with the previous. // Close the command encoder, and swap it with the previous.
encoder.close_and_swap().map_pass_err(pass_scope)?; encoder.close_and_swap().map_pass_err(pass_scope)?;
Ok(()) Ok(())
@ -782,7 +781,7 @@ impl Global {
fn set_pipeline( fn set_pipeline(
state: &mut State, state: &mut State,
cmd_buf: &CommandBuffer, cmd_buf: &CommandEncoder,
pipeline: Arc<ComputePipeline>, pipeline: Arc<ComputePipeline>,
) -> Result<(), ComputePassErrorInner> { ) -> Result<(), ComputePassErrorInner> {
pipeline.same_device_as(cmd_buf)?; pipeline.same_device_as(cmd_buf)?;
@ -859,7 +858,7 @@ fn dispatch(state: &mut State, groups: [u32; 3]) -> Result<(), ComputePassErrorI
fn dispatch_indirect( fn dispatch_indirect(
state: &mut State, state: &mut State,
cmd_buf: &CommandBuffer, cmd_buf: &CommandEncoder,
buffer: Arc<Buffer>, buffer: Arc<Buffer>,
offset: u64, offset: u64,
) -> Result<(), ComputePassErrorInner> { ) -> Result<(), ComputePassErrorInner> {

View File

@ -145,6 +145,9 @@ impl CommandEncoderStatus {
// Encoder is ended. Invalidate the encoder, do not record anything, // Encoder is ended. Invalidate the encoder, do not record anything,
// and return an immediate validation error. // and return an immediate validation error.
Self::Finished(_) => Err(self.invalidate(EncoderStateError::Ended)), Self::Finished(_) => Err(self.invalidate(EncoderStateError::Ended)),
Self::Error(CommandEncoderError::State(EncoderStateError::Ended)) => {
Err(EncoderStateError::Ended)
}
// Encoder is already invalid. Do not record anything, but do not // Encoder is already invalid. Do not record anything, but do not
// return an immediate validation error. // return an immediate validation error.
Self::Error(_) => Ok(()), Self::Error(_) => Ok(()),
@ -173,6 +176,7 @@ impl CommandEncoderStatus {
self.invalidate(EncoderStateError::Ended); self.invalidate(EncoderStateError::Ended);
f(None) f(None)
} }
Self::Error(CommandEncoderError::State(EncoderStateError::Ended)) => f(None),
Self::Error(_) => f(None), Self::Error(_) => f(None),
Self::Transitioning => unreachable!(), Self::Transitioning => unreachable!(),
} }
@ -210,6 +214,10 @@ impl CommandEncoderStatus {
Err(EncoderStateError::Ended) Err(EncoderStateError::Ended)
} }
Self::Locked(_) => Err(self.invalidate(EncoderStateError::Locked)), Self::Locked(_) => Err(self.invalidate(EncoderStateError::Locked)),
st @ Self::Error(CommandEncoderError::State(EncoderStateError::Ended)) => {
*self = st;
Err(EncoderStateError::Ended)
}
st @ Self::Error(_) => { st @ Self::Error(_) => {
*self = st; *self = st;
Err(EncoderStateError::Invalid) Err(EncoderStateError::Invalid)
@ -254,6 +262,10 @@ impl CommandEncoderStatus {
*self = Self::Error(EncoderStateError::Unlocked.into()); *self = Self::Error(EncoderStateError::Unlocked.into());
Err(EncoderStateError::Unlocked) Err(EncoderStateError::Unlocked)
} }
st @ Self::Error(CommandEncoderError::State(EncoderStateError::Ended)) => {
*self = st;
Err(EncoderStateError::Ended)
}
st @ Self::Error(_) => { st @ Self::Error(_) => {
// Encoder is invalid. Do not record anything, but do not // Encoder is invalid. Do not record anything, but do not
// return an immediate validation error. // return an immediate validation error.
@ -374,6 +386,26 @@ impl<'a> ops::DerefMut for RecordingGuard<'a> {
} }
} }
pub(crate) struct CommandEncoder {
pub(crate) device: Arc<Device>,
pub(crate) label: String,
/// The mutable state of this command encoder.
pub(crate) data: Mutex<CommandEncoderStatus>,
}
crate::impl_resource_type!(CommandEncoder);
crate::impl_labeled!(CommandEncoder);
crate::impl_parent_device!(CommandEncoder);
crate::impl_storage_item!(CommandEncoder);
impl Drop for CommandEncoder {
fn drop(&mut self) {
resource_log!("Drop {}", self.error_ident());
}
}
/// A raw [`CommandEncoder`][rce], and the raw [`CommandBuffer`][rcb]s built from it. /// A raw [`CommandEncoder`][rce], and the raw [`CommandBuffer`][rcb]s built from it.
/// ///
/// Each wgpu-core [`CommandBuffer`] owns an instance of this type, which is /// Each wgpu-core [`CommandBuffer`] owns an instance of this type, which is
@ -385,16 +417,11 @@ impl<'a> ops::DerefMut for RecordingGuard<'a> {
/// commands into the middle of a recorded stream. However, hal queue submission /// commands into the middle of a recorded stream. However, hal queue submission
/// accepts a series of command buffers at once, so we can simply break the /// accepts a series of command buffers at once, so we can simply break the
/// stream up into multiple buffers, and then reorder the buffers. See /// stream up into multiple buffers, and then reorder the buffers. See
/// [`CommandEncoder::close_and_swap`] for a specific example of this. /// [`InnerCommandEncoder::close_and_swap`] for a specific example of this.
///
/// Note that a [`CommandEncoderId`] actually refers to a [`CommandBuffer`].
/// Methods that take a command encoder id actually look up the command buffer,
/// and then use its encoder.
/// ///
/// [rce]: hal::Api::CommandEncoder /// [rce]: hal::Api::CommandEncoder
/// [rcb]: hal::Api::CommandBuffer /// [rcb]: hal::Api::CommandBuffer
/// [`CommandEncoderId`]: crate::id::CommandEncoderId pub(crate) struct InnerCommandEncoder {
pub(crate) struct CommandEncoder {
/// The underlying `wgpu_hal` [`CommandEncoder`]. /// The underlying `wgpu_hal` [`CommandEncoder`].
/// ///
/// Successfully executed command buffers' encoders are saved in a /// Successfully executed command buffers' encoders are saved in a
@ -427,10 +454,10 @@ pub(crate) struct CommandEncoder {
/// [`wgpu_hal::CommandEncoder`]: hal::CommandEncoder /// [`wgpu_hal::CommandEncoder`]: hal::CommandEncoder
pub(crate) is_open: bool, pub(crate) is_open: bool,
pub(crate) hal_label: Option<String>, pub(crate) label: String,
} }
impl CommandEncoder { impl InnerCommandEncoder {
/// Finish the current command buffer and insert it just before /// Finish the current command buffer and insert it just before
/// the last element in [`self.list`][l]. /// the last element in [`self.list`][l].
/// ///
@ -453,7 +480,7 @@ impl CommandEncoder {
/// ///
/// - If the encoder is not open. /// - If the encoder is not open.
/// ///
/// [l]: CommandEncoder::list /// [l]: InnerCommandEncoder::list
/// [`transition_buffers`]: hal::CommandEncoder::transition_buffers /// [`transition_buffers`]: hal::CommandEncoder::transition_buffers
/// [`transition_textures`]: hal::CommandEncoder::transition_textures /// [`transition_textures`]: hal::CommandEncoder::transition_textures
fn close_and_swap(&mut self) -> Result<(), DeviceError> { fn close_and_swap(&mut self) -> Result<(), DeviceError> {
@ -476,7 +503,7 @@ impl CommandEncoder {
/// ///
/// - If the encoder is not open. /// - If the encoder is not open.
/// ///
/// [l]: CommandEncoder::list /// [l]: InnerCommandEncoder::list
pub(crate) fn close_and_push_front(&mut self) -> Result<(), DeviceError> { pub(crate) fn close_and_push_front(&mut self) -> Result<(), DeviceError> {
assert!(self.is_open); assert!(self.is_open);
self.is_open = false; self.is_open = false;
@ -497,7 +524,7 @@ impl CommandEncoder {
/// ///
/// - If the encoder is not open. /// - If the encoder is not open.
/// ///
/// [l]: CommandEncoder::list /// [l]: InnerCommandEncoder::list
pub(crate) fn close(&mut self) -> Result<(), DeviceError> { pub(crate) fn close(&mut self) -> Result<(), DeviceError> {
assert!(self.is_open); assert!(self.is_open);
self.is_open = false; self.is_open = false;
@ -518,7 +545,7 @@ impl CommandEncoder {
/// ///
/// On return, the underlying hal encoder is closed. /// On return, the underlying hal encoder is closed.
/// ///
/// [l]: CommandEncoder::list /// [l]: InnerCommandEncoder::list
fn close_if_open(&mut self) -> Result<(), DeviceError> { fn close_if_open(&mut self) -> Result<(), DeviceError> {
if self.is_open { if self.is_open {
self.is_open = false; self.is_open = false;
@ -536,7 +563,7 @@ impl CommandEncoder {
pub(crate) fn open(&mut self) -> Result<&mut dyn hal::DynCommandEncoder, DeviceError> { pub(crate) fn open(&mut self) -> Result<&mut dyn hal::DynCommandEncoder, DeviceError> {
if !self.is_open { if !self.is_open {
self.is_open = true; self.is_open = true;
let hal_label = self.hal_label.as_deref(); let hal_label = hal_label(Some(&self.label), self.device.instance_flags);
unsafe { self.raw.begin_encoding(hal_label) } unsafe { self.raw.begin_encoding(hal_label) }
.map_err(|e| self.device.handle_hal_error(e))?; .map_err(|e| self.device.handle_hal_error(e))?;
} }
@ -567,7 +594,7 @@ impl CommandEncoder {
} }
} }
impl Drop for CommandEncoder { impl Drop for InnerCommandEncoder {
fn drop(&mut self) { fn drop(&mut self) {
if self.is_open { if self.is_open {
unsafe { self.raw.discard_encoding() }; unsafe { self.raw.discard_encoding() };
@ -584,7 +611,7 @@ impl Drop for CommandEncoder {
/// Look at the documentation for [`CommandBufferMutable`] for an explanation of /// Look at the documentation for [`CommandBufferMutable`] for an explanation of
/// the fields in this struct. This is the "built" counterpart to that type. /// the fields in this struct. This is the "built" counterpart to that type.
pub(crate) struct BakedCommands { pub(crate) struct BakedCommands {
pub(crate) encoder: CommandEncoder, pub(crate) encoder: InnerCommandEncoder,
pub(crate) trackers: Tracker, pub(crate) trackers: Tracker,
pub(crate) temp_resources: Vec<TempResource>, pub(crate) temp_resources: Vec<TempResource>,
pub(crate) indirect_draw_validation_resources: crate::indirect_validation::DrawResources, pub(crate) indirect_draw_validation_resources: crate::indirect_validation::DrawResources,
@ -598,7 +625,7 @@ pub struct CommandBufferMutable {
/// they belong to. /// they belong to.
/// ///
/// [`wgpu_hal::Api::CommandBuffer`]: hal::Api::CommandBuffer /// [`wgpu_hal::Api::CommandBuffer`]: hal::Api::CommandBuffer
pub(crate) encoder: CommandEncoder, pub(crate) encoder: InnerCommandEncoder,
/// All the resources that the commands recorded so far have referred to. /// All the resources that the commands recorded so far have referred to.
pub(crate) trackers: Tracker, pub(crate) trackers: Tracker,
@ -647,25 +674,11 @@ impl CommandBufferMutable {
/// A buffer of commands to be submitted to the GPU for execution. /// A buffer of commands to be submitted to the GPU for execution.
/// ///
/// Whereas the WebGPU API uses two separate types for command buffers and /// Once a command buffer is submitted to the queue, its contents are taken
/// encoders, this type is a fusion of the two: /// to construct a [`BakedCommands`], whose contents eventually become the
/// /// property of the submission queue.
/// - During command recording, this holds a [`CommandEncoder`] accepting this
/// buffer's commands. In this state, the [`CommandBuffer`] type behaves like
/// a WebGPU `GPUCommandEncoder`.
///
/// - Once command recording is finished by calling
/// [`Global::command_encoder_finish`], no further recording is allowed. The
/// internal [`CommandEncoder`] is retained solely as a storage pool for the
/// raw command buffers. In this state, the value behaves like a WebGPU
/// `GPUCommandBuffer`.
///
/// - Once a command buffer is submitted to the queue, it is removed from the id
/// registry, and its contents are taken to construct a [`BakedCommands`],
/// whose contents eventually become the property of the submission queue.
pub struct CommandBuffer { pub struct CommandBuffer {
pub(crate) device: Arc<Device>, pub(crate) device: Arc<Device>,
support_clear_texture: bool,
/// The `label` from the descriptor used to create the resource. /// The `label` from the descriptor used to create the resource.
label: String, label: String,
@ -679,25 +692,24 @@ impl Drop for CommandBuffer {
} }
} }
impl CommandBuffer { impl CommandEncoder {
pub(crate) fn new( pub(crate) fn new(
encoder: Box<dyn hal::DynCommandEncoder>, encoder: Box<dyn hal::DynCommandEncoder>,
device: &Arc<Device>, device: &Arc<Device>,
label: &Label, label: &Label,
) -> Self { ) -> Self {
CommandBuffer { CommandEncoder {
device: device.clone(), device: device.clone(),
support_clear_texture: device.features.contains(wgt::Features::CLEAR_TEXTURE),
label: label.to_string(), label: label.to_string(),
data: Mutex::new( data: Mutex::new(
rank::COMMAND_BUFFER_DATA, rank::COMMAND_BUFFER_DATA,
CommandEncoderStatus::Recording(CommandBufferMutable { CommandEncoderStatus::Recording(CommandBufferMutable {
encoder: CommandEncoder { encoder: InnerCommandEncoder {
raw: ManuallyDrop::new(encoder), raw: ManuallyDrop::new(encoder),
list: Vec::new(), list: Vec::new(),
device: device.clone(), device: device.clone(),
is_open: false, is_open: false,
hal_label: label.to_hal(device.instance_flags).map(str::to_owned), label: label.to_string(),
}, },
trackers: Tracker::new(), trackers: Tracker::new(),
buffer_memory_init_actions: Default::default(), buffer_memory_init_actions: Default::default(),
@ -723,9 +735,8 @@ impl CommandBuffer {
label: &Label, label: &Label,
err: CommandEncoderError, err: CommandEncoderError,
) -> Self { ) -> Self {
CommandBuffer { CommandEncoder {
device: device.clone(), device: device.clone(),
support_clear_texture: device.features.contains(wgt::Features::CLEAR_TEXTURE),
label: label.to_string(), label: label.to_string(),
data: Mutex::new(rank::COMMAND_BUFFER_DATA, CommandEncoderStatus::Error(err)), data: Mutex::new(rank::COMMAND_BUFFER_DATA, CommandEncoderStatus::Error(err)),
} }
@ -1123,22 +1134,40 @@ impl Global {
pub fn command_encoder_finish( pub fn command_encoder_finish(
&self, &self,
encoder_id: id::CommandEncoderId, encoder_id: id::CommandEncoderId,
_desc: &wgt::CommandBufferDescriptor<Label>, desc: &wgt::CommandBufferDescriptor<Label>,
id_in: Option<id::CommandBufferId>,
) -> (id::CommandBufferId, Option<CommandEncoderError>) { ) -> (id::CommandBufferId, Option<CommandEncoderError>) {
profiling::scope!("CommandEncoder::finish"); profiling::scope!("CommandEncoder::finish");
let hub = &self.hub; let hub = &self.hub;
let cmd_buf = hub.command_buffers.get(encoder_id.into_command_buffer_id()); let cmd_enc = hub.command_encoders.get(encoder_id);
let mut data_guard = cmd_enc.data.lock();
// Errors related to destroyed resources are not reported until the // Errors related to destroyed resources are not reported until the
// command buffer is submitted. // command buffer is submitted.
let error = match cmd_buf.data.lock().finish() { let error = match data_guard.finish() {
Err(e) if !e.is_destroyed_error() => Some(e), Err(e) if !e.is_destroyed_error() => Some(e),
_ => None, _ => None,
}; };
(encoder_id.into_command_buffer_id(), error) let data = mem::replace(
&mut *data_guard,
CommandEncoderStatus::Error(EncoderStateError::Ended.into()),
);
drop(data_guard);
let cmd_buf = CommandBuffer {
device: cmd_enc.device.clone(),
label: desc.label.to_string(),
data: Mutex::new(rank::COMMAND_BUFFER_DATA, data),
};
let cmd_buf_id = hub.command_buffers.prepare(id_in).assign(Arc::new(cmd_buf));
(cmd_buf_id, error)
} }
pub fn command_encoder_push_debug_group( pub fn command_encoder_push_debug_group(
@ -1151,7 +1180,7 @@ impl Global {
let hub = &self.hub; let hub = &self.hub;
let cmd_buf = hub.command_buffers.get(encoder_id.into_command_buffer_id()); let cmd_buf = hub.command_encoders.get(encoder_id);
let mut cmd_buf_data = cmd_buf.data.lock(); let mut cmd_buf_data = cmd_buf.data.lock();
cmd_buf_data.record_with(|cmd_buf_data| -> Result<(), CommandEncoderError> { cmd_buf_data.record_with(|cmd_buf_data| -> Result<(), CommandEncoderError> {
#[cfg(feature = "trace")] #[cfg(feature = "trace")]
@ -1186,7 +1215,7 @@ impl Global {
let hub = &self.hub; let hub = &self.hub;
let cmd_buf = hub.command_buffers.get(encoder_id.into_command_buffer_id()); let cmd_buf = hub.command_encoders.get(encoder_id);
let mut cmd_buf_data = cmd_buf.data.lock(); let mut cmd_buf_data = cmd_buf.data.lock();
cmd_buf_data.record_with(|cmd_buf_data| -> Result<(), CommandEncoderError> { cmd_buf_data.record_with(|cmd_buf_data| -> Result<(), CommandEncoderError> {
#[cfg(feature = "trace")] #[cfg(feature = "trace")]
@ -1220,7 +1249,7 @@ impl Global {
let hub = &self.hub; let hub = &self.hub;
let cmd_buf = hub.command_buffers.get(encoder_id.into_command_buffer_id()); let cmd_buf = hub.command_encoders.get(encoder_id);
let mut cmd_buf_data = cmd_buf.data.lock(); let mut cmd_buf_data = cmd_buf.data.lock();
cmd_buf_data.record_with(|cmd_buf_data| -> Result<(), CommandEncoderError> { cmd_buf_data.record_with(|cmd_buf_data| -> Result<(), CommandEncoderError> {
#[cfg(feature = "trace")] #[cfg(feature = "trace")]

View File

@ -3,7 +3,7 @@
use crate::binding_model::{BindError, BindGroup, PushConstantUploadError}; use crate::binding_model::{BindError, BindGroup, PushConstantUploadError};
use crate::command::bind::Binder; use crate::command::bind::Binder;
use crate::command::memory_init::{CommandBufferTextureMemoryActions, SurfacesInDiscardState}; use crate::command::memory_init::{CommandBufferTextureMemoryActions, SurfacesInDiscardState};
use crate::command::{CommandBuffer, QueryResetMap, QueryUseError}; use crate::command::{CommandEncoder, QueryResetMap, QueryUseError};
use crate::device::{Device, DeviceError, MissingFeatures}; use crate::device::{Device, DeviceError, MissingFeatures};
use crate::init_tracker::BufferInitTrackerAction; use crate::init_tracker::BufferInitTrackerAction;
use crate::pipeline::LateSizedBufferGroup; use crate::pipeline::LateSizedBufferGroup;
@ -82,7 +82,7 @@ pub(crate) struct BaseState<'scope, 'snatch_guard, 'cmd_buf, 'raw_encoder> {
pub(crate) fn set_bind_group<E>( pub(crate) fn set_bind_group<E>(
state: &mut BaseState, state: &mut BaseState,
cmd_buf: &CommandBuffer, cmd_buf: &CommandEncoder,
dynamic_offsets: &[DynamicOffset], dynamic_offsets: &[DynamicOffset],
index: u32, index: u32,
num_dynamic_offsets: usize, num_dynamic_offsets: usize,
@ -287,7 +287,7 @@ where
pub(crate) fn write_timestamp<E>( pub(crate) fn write_timestamp<E>(
state: &mut BaseState, state: &mut BaseState,
cmd_buf: &CommandBuffer, cmd_buf: &CommandEncoder,
pending_query_resets: Option<&mut QueryResetMap>, pending_query_resets: Option<&mut QueryResetMap>,
query_set: Arc<QuerySet>, query_set: Arc<QuerySet>,
query_index: u32, query_index: u32,

View File

@ -4,7 +4,7 @@ use core::{iter, mem};
#[cfg(feature = "trace")] #[cfg(feature = "trace")]
use crate::device::trace::Command as TraceCommand; use crate::device::trace::Command as TraceCommand;
use crate::{ use crate::{
command::{CommandBuffer, EncoderStateError}, command::{CommandEncoder, EncoderStateError},
device::{DeviceError, MissingFeatures}, device::{DeviceError, MissingFeatures},
global::Global, global::Global,
id, id,
@ -307,7 +307,7 @@ pub(super) fn validate_and_begin_pipeline_statistics_query(
query_set: Arc<QuerySet>, query_set: Arc<QuerySet>,
raw_encoder: &mut dyn hal::DynCommandEncoder, raw_encoder: &mut dyn hal::DynCommandEncoder,
tracker: &mut StatelessTracker<QuerySet>, tracker: &mut StatelessTracker<QuerySet>,
cmd_buf: &CommandBuffer, cmd_buf: &CommandEncoder,
query_index: u32, query_index: u32,
reset_state: Option<&mut QueryResetMap>, reset_state: Option<&mut QueryResetMap>,
active_query: &mut Option<(Arc<QuerySet>, u32)>, active_query: &mut Option<(Arc<QuerySet>, u32)>,
@ -363,9 +363,7 @@ impl Global {
) -> Result<(), EncoderStateError> { ) -> Result<(), EncoderStateError> {
let hub = &self.hub; let hub = &self.hub;
let cmd_buf = hub let cmd_buf = hub.command_encoders.get(command_encoder_id);
.command_buffers
.get(command_encoder_id.into_command_buffer_id());
let mut cmd_buf_data = cmd_buf.data.lock(); let mut cmd_buf_data = cmd_buf.data.lock();
cmd_buf_data.record_with(|cmd_buf_data| -> Result<(), QueryError> { cmd_buf_data.record_with(|cmd_buf_data| -> Result<(), QueryError> {
#[cfg(feature = "trace")] #[cfg(feature = "trace")]
@ -406,9 +404,7 @@ impl Global {
) -> Result<(), EncoderStateError> { ) -> Result<(), EncoderStateError> {
let hub = &self.hub; let hub = &self.hub;
let cmd_buf = hub let cmd_buf = hub.command_encoders.get(command_encoder_id);
.command_buffers
.get(command_encoder_id.into_command_buffer_id());
let mut cmd_buf_data = cmd_buf.data.lock(); let mut cmd_buf_data = cmd_buf.data.lock();
cmd_buf_data.record_with(|cmd_buf_data| -> Result<(), QueryError> { cmd_buf_data.record_with(|cmd_buf_data| -> Result<(), QueryError> {
#[cfg(feature = "trace")] #[cfg(feature = "trace")]

View File

@ -67,9 +67,7 @@ impl Global {
let hub = &self.hub; let hub = &self.hub;
let cmd_buf = hub let cmd_buf = hub.command_encoders.get(command_encoder_id);
.command_buffers
.get(command_encoder_id.into_command_buffer_id());
let mut cmd_buf_data = cmd_buf.data.lock(); let mut cmd_buf_data = cmd_buf.data.lock();
cmd_buf_data.record_with( cmd_buf_data.record_with(
@ -109,9 +107,7 @@ impl Global {
let hub = &self.hub; let hub = &self.hub;
let cmd_buf = hub let cmd_buf = hub.command_encoders.get(command_encoder_id);
.command_buffers
.get(command_encoder_id.into_command_buffer_id());
let mut build_command = AsBuild::default(); let mut build_command = AsBuild::default();

View File

@ -11,8 +11,8 @@ use wgt::{
use crate::command::{ use crate::command::{
pass, pass_base, pass_try, validate_and_begin_occlusion_query, pass, pass_base, pass_try, validate_and_begin_occlusion_query,
validate_and_begin_pipeline_statistics_query, EncoderStateError, PassStateError, validate_and_begin_pipeline_statistics_query, EncoderStateError, InnerCommandEncoder,
TimestampWritesError, PassStateError, TimestampWritesError,
}; };
use crate::pipeline::{RenderPipeline, VertexStep}; use crate::pipeline::{RenderPipeline, VertexStep};
use crate::resource::RawResourceAccess; use crate::resource::RawResourceAccess;
@ -24,8 +24,8 @@ use crate::{
bind::Binder, bind::Binder,
end_occlusion_query, end_pipeline_statistics_query, end_occlusion_query, end_pipeline_statistics_query,
memory_init::{fixup_discarded_surfaces, SurfacesInDiscardState}, memory_init::{fixup_discarded_surfaces, SurfacesInDiscardState},
ArcPassTimestampWrites, BasePass, BindGroupStateChange, CommandBuffer, CommandEncoderError, ArcPassTimestampWrites, BasePass, BindGroupStateChange, CommandEncoderError, DrawError,
DrawError, ExecutionError, MapPassErr, PassErrorScope, PassTimestampWrites, QueryUseError, ExecutionError, MapPassErr, PassErrorScope, PassTimestampWrites, QueryUseError,
RenderCommandError, StateChange, RenderCommandError, StateChange,
}, },
device::{ device::{
@ -258,12 +258,12 @@ pub struct RenderPass {
/// All pass data & records is stored here. /// All pass data & records is stored here.
base: BasePass<ArcRenderCommand, RenderPassError>, base: BasePass<ArcRenderCommand, RenderPassError>,
/// Parent command buffer that this pass records commands into. /// Parent command encoder that this pass records commands into.
/// ///
/// If this is `Some`, then the pass is in WebGPU's "open" state. If it is /// If this is `Some`, then the pass is in WebGPU's "open" state. If it is
/// `None`, then the pass is in the "ended" state. /// `None`, then the pass is in the "ended" state.
/// See <https://www.w3.org/TR/webgpu/#encoder-state> /// See <https://www.w3.org/TR/webgpu/#encoder-state>
parent: Option<Arc<CommandBuffer>>, parent: Option<Arc<CommandEncoder>>,
color_attachments: color_attachments:
ArrayVec<Option<ArcRenderPassColorAttachment>, { hal::MAX_COLOR_ATTACHMENTS }>, ArrayVec<Option<ArcRenderPassColorAttachment>, { hal::MAX_COLOR_ATTACHMENTS }>,
@ -277,8 +277,8 @@ pub struct RenderPass {
} }
impl RenderPass { impl RenderPass {
/// If the parent command buffer is invalid, the returned pass will be invalid. /// If the parent command encoder is invalid, the returned pass will be invalid.
fn new(parent: Arc<CommandBuffer>, desc: ArcRenderPassDescriptor) -> Self { fn new(parent: Arc<CommandEncoder>, desc: ArcRenderPassDescriptor) -> Self {
let ArcRenderPassDescriptor { let ArcRenderPassDescriptor {
label, label,
timestamp_writes, timestamp_writes,
@ -300,7 +300,7 @@ impl RenderPass {
} }
} }
fn new_invalid(parent: Arc<CommandBuffer>, label: &Label, err: RenderPassError) -> Self { fn new_invalid(parent: Arc<CommandEncoder>, label: &Label, err: RenderPassError) -> Self {
Self { Self {
base: BasePass::new_invalid(label, err), base: BasePass::new_invalid(label, err),
parent: Some(parent), parent: Some(parent),
@ -955,7 +955,7 @@ impl RenderPassInfo {
mut depth_stencil_attachment: Option<ArcRenderPassDepthStencilAttachment>, mut depth_stencil_attachment: Option<ArcRenderPassDepthStencilAttachment>,
mut timestamp_writes: Option<ArcPassTimestampWrites>, mut timestamp_writes: Option<ArcPassTimestampWrites>,
mut occlusion_query_set: Option<Arc<QuerySet>>, mut occlusion_query_set: Option<Arc<QuerySet>>,
encoder: &mut CommandEncoder, encoder: &mut InnerCommandEncoder,
trackers: &mut Tracker, trackers: &mut Tracker,
texture_memory_actions: &mut CommandBufferTextureMemoryActions, texture_memory_actions: &mut CommandBufferTextureMemoryActions,
pending_query_resets: &mut QueryResetMap, pending_query_resets: &mut QueryResetMap,
@ -1665,7 +1665,7 @@ impl Global {
let scope = PassErrorScope::Pass; let scope = PassErrorScope::Pass;
let hub = &self.hub; let hub = &self.hub;
let cmd_buf = hub.command_buffers.get(encoder_id.into_command_buffer_id()); let cmd_buf = hub.command_encoders.get(encoder_id);
let mut cmd_buf_data = cmd_buf.data.lock(); let mut cmd_buf_data = cmd_buf.data.lock();
match cmd_buf_data.lock_encoder() { match cmd_buf_data.lock_encoder() {
@ -1739,10 +1739,7 @@ impl Global {
) { ) {
#[cfg(feature = "trace")] #[cfg(feature = "trace")]
{ {
let cmd_buf = self let cmd_buf = self.hub.command_encoders.get(encoder_id);
.hub
.command_buffers
.get(encoder_id.into_command_buffer_id());
let mut cmd_buf_data = cmd_buf.data.lock(); let mut cmd_buf_data = cmd_buf.data.lock();
let cmd_buf_data = cmd_buf_data.get_inner(); let cmd_buf_data = cmd_buf_data.get_inner();
@ -2233,7 +2230,7 @@ impl Global {
cmd_buf_data.pending_query_resets.reset_queries(transit); cmd_buf_data.pending_query_resets.reset_queries(transit);
CommandBuffer::insert_barriers_from_scope(transit, tracker, &scope, snatch_guard); CommandEncoder::insert_barriers_from_scope(transit, tracker, &scope, snatch_guard);
if let Some(ref indirect_validation) = device.indirect_validation { if let Some(ref indirect_validation) = device.indirect_validation {
indirect_validation indirect_validation
@ -2259,7 +2256,7 @@ impl Global {
fn set_pipeline( fn set_pipeline(
state: &mut State, state: &mut State,
cmd_buf: &Arc<CommandBuffer>, cmd_buf: &Arc<CommandEncoder>,
pipeline: Arc<RenderPipeline>, pipeline: Arc<RenderPipeline>,
) -> Result<(), RenderPassErrorInner> { ) -> Result<(), RenderPassErrorInner> {
api_log!("RenderPass::set_pipeline {}", pipeline.error_ident()); api_log!("RenderPass::set_pipeline {}", pipeline.error_ident());
@ -2326,7 +2323,7 @@ fn set_pipeline(
// This function is duplicative of `bundle::set_index_buffer`. // This function is duplicative of `bundle::set_index_buffer`.
fn set_index_buffer( fn set_index_buffer(
state: &mut State, state: &mut State,
cmd_buf: &Arc<CommandBuffer>, cmd_buf: &Arc<CommandEncoder>,
buffer: Arc<crate::resource::Buffer>, buffer: Arc<crate::resource::Buffer>,
index_format: IndexFormat, index_format: IndexFormat,
offset: u64, offset: u64,
@ -2374,7 +2371,7 @@ fn set_index_buffer(
// This function is duplicative of `render::set_vertex_buffer`. // This function is duplicative of `render::set_vertex_buffer`.
fn set_vertex_buffer( fn set_vertex_buffer(
state: &mut State, state: &mut State,
cmd_buf: &Arc<CommandBuffer>, cmd_buf: &Arc<CommandEncoder>,
slot: u32, slot: u32,
buffer: Arc<crate::resource::Buffer>, buffer: Arc<crate::resource::Buffer>,
offset: u64, offset: u64,
@ -2607,7 +2604,7 @@ fn multi_draw_indirect(
state: &mut State, state: &mut State,
indirect_draw_validation_resources: &mut crate::indirect_validation::DrawResources, indirect_draw_validation_resources: &mut crate::indirect_validation::DrawResources,
indirect_draw_validation_batcher: &mut crate::indirect_validation::DrawBatcher, indirect_draw_validation_batcher: &mut crate::indirect_validation::DrawBatcher,
cmd_buf: &Arc<CommandBuffer>, cmd_buf: &Arc<CommandEncoder>,
indirect_buffer: Arc<crate::resource::Buffer>, indirect_buffer: Arc<crate::resource::Buffer>,
offset: u64, offset: u64,
count: u32, count: u32,
@ -2788,7 +2785,7 @@ fn multi_draw_indirect(
fn multi_draw_indirect_count( fn multi_draw_indirect_count(
state: &mut State, state: &mut State,
cmd_buf: &Arc<CommandBuffer>, cmd_buf: &Arc<CommandEncoder>,
indirect_buffer: Arc<crate::resource::Buffer>, indirect_buffer: Arc<crate::resource::Buffer>,
offset: u64, offset: u64,
count_buffer: Arc<crate::resource::Buffer>, count_buffer: Arc<crate::resource::Buffer>,
@ -2901,7 +2898,7 @@ fn execute_bundle(
state: &mut State, state: &mut State,
indirect_draw_validation_resources: &mut crate::indirect_validation::DrawResources, indirect_draw_validation_resources: &mut crate::indirect_validation::DrawResources,
indirect_draw_validation_batcher: &mut crate::indirect_validation::DrawBatcher, indirect_draw_validation_batcher: &mut crate::indirect_validation::DrawBatcher,
cmd_buf: &Arc<CommandBuffer>, cmd_buf: &Arc<CommandEncoder>,
bundle: Arc<super::RenderBundle>, bundle: Arc<super::RenderBundle>,
) -> Result<(), RenderPassErrorInner> { ) -> Result<(), RenderPassErrorInner> {
api_log!("RenderPass::execute_bundle {}", bundle.error_ident()); api_log!("RenderPass::execute_bundle {}", bundle.error_ident());

View File

@ -640,9 +640,7 @@ impl Global {
let hub = &self.hub; let hub = &self.hub;
let cmd_buf = hub let cmd_buf = hub.command_encoders.get(command_encoder_id);
.command_buffers
.get(command_encoder_id.into_command_buffer_id());
let mut cmd_buf_data = cmd_buf.data.lock(); let mut cmd_buf_data = cmd_buf.data.lock();
cmd_buf_data.record_with(|cmd_buf_data| -> Result<(), CommandEncoderError> { cmd_buf_data.record_with(|cmd_buf_data| -> Result<(), CommandEncoderError> {
let device = &cmd_buf.device; let device = &cmd_buf.device;
@ -809,9 +807,7 @@ impl Global {
let hub = &self.hub; let hub = &self.hub;
let cmd_buf = hub let cmd_buf = hub.command_encoders.get(command_encoder_id);
.command_buffers
.get(command_encoder_id.into_command_buffer_id());
let mut cmd_buf_data = cmd_buf.data.lock(); let mut cmd_buf_data = cmd_buf.data.lock();
cmd_buf_data.record_with(|cmd_buf_data| -> Result<(), CommandEncoderError> { cmd_buf_data.record_with(|cmd_buf_data| -> Result<(), CommandEncoderError> {
let device = &cmd_buf.device; let device = &cmd_buf.device;
@ -967,9 +963,7 @@ impl Global {
let hub = &self.hub; let hub = &self.hub;
let cmd_buf = hub let cmd_buf = hub.command_encoders.get(command_encoder_id);
.command_buffers
.get(command_encoder_id.into_command_buffer_id());
let mut cmd_buf_data = cmd_buf.data.lock(); let mut cmd_buf_data = cmd_buf.data.lock();
cmd_buf_data.record_with(|cmd_buf_data| -> Result<(), CommandEncoderError> { cmd_buf_data.record_with(|cmd_buf_data| -> Result<(), CommandEncoderError> {
let device = &cmd_buf.device; let device = &cmd_buf.device;
@ -1142,9 +1136,7 @@ impl Global {
let hub = &self.hub; let hub = &self.hub;
let cmd_buf = hub let cmd_buf = hub.command_encoders.get(command_encoder_id);
.command_buffers
.get(command_encoder_id.into_command_buffer_id());
let mut cmd_buf_data = cmd_buf.data.lock(); let mut cmd_buf_data = cmd_buf.data.lock();
cmd_buf_data.record_with(|cmd_buf_data| -> Result<(), CommandEncoderError> { cmd_buf_data.record_with(|cmd_buf_data| -> Result<(), CommandEncoderError> {
let device = &cmd_buf.device; let device = &cmd_buf.device;

View File

@ -2,7 +2,7 @@ use thiserror::Error;
use wgt::error::{ErrorType, WebGpuError}; use wgt::error::{ErrorType, WebGpuError};
use crate::{ use crate::{
command::{CommandBuffer, CommandEncoderError, EncoderStateError}, command::{CommandEncoder, CommandEncoderError, EncoderStateError},
device::DeviceError, device::DeviceError,
global::Global, global::Global,
id::{BufferId, CommandEncoderId, TextureId}, id::{BufferId, CommandEncoderId, TextureId},
@ -22,9 +22,7 @@ impl Global {
let hub = &self.hub; let hub = &self.hub;
// Lock command encoder for recording // Lock command encoder for recording
let cmd_buf = hub let cmd_buf = hub.command_encoders.get(command_encoder_id);
.command_buffers
.get(command_encoder_id.into_command_buffer_id());
let mut cmd_buf_data = cmd_buf.data.lock(); let mut cmd_buf_data = cmd_buf.data.lock();
cmd_buf_data.record_with(|cmd_buf_data| -> Result<(), CommandEncoderError> { cmd_buf_data.record_with(|cmd_buf_data| -> Result<(), CommandEncoderError> {
// Get and lock device // Get and lock device
@ -63,7 +61,7 @@ impl Global {
// Record any needed barriers based on tracker data // Record any needed barriers based on tracker data
let cmd_buf_raw = cmd_buf_data.encoder.open()?; let cmd_buf_raw = cmd_buf_data.encoder.open()?;
CommandBuffer::insert_barriers_from_scope( CommandEncoder::insert_barriers_from_scope(
cmd_buf_raw, cmd_buf_raw,
&mut cmd_buf_data.trackers, &mut cmd_buf_data.trackers,
&usage_scope, &usage_scope,

View File

@ -9,7 +9,7 @@ use crate::{
self, BindGroupEntry, BindingResource, BufferBinding, ResolvedBindGroupDescriptor, self, BindGroupEntry, BindingResource, BufferBinding, ResolvedBindGroupDescriptor,
ResolvedBindGroupEntry, ResolvedBindingResource, ResolvedBufferBinding, ResolvedBindGroupEntry, ResolvedBindingResource, ResolvedBufferBinding,
}, },
command::{self, CommandBuffer}, command::{self, CommandEncoder},
conv, conv,
device::{bgl, life::WaitIdleError, DeviceError, DeviceLostClosure}, device::{bgl, life::WaitIdleError, DeviceError, DeviceLostClosure},
global::Global, global::Global,
@ -1051,46 +1051,39 @@ impl Global {
profiling::scope!("Device::create_command_encoder"); profiling::scope!("Device::create_command_encoder");
let hub = &self.hub; let hub = &self.hub;
let fid = hub let fid = hub.command_encoders.prepare(id_in);
.command_buffers
.prepare(id_in.map(|id| id.into_command_buffer_id()));
let device = self.hub.devices.get(device_id); let device = self.hub.devices.get(device_id);
let error = 'error: { let error = 'error: {
let command_buffer = match device.create_command_encoder(&desc.label) { let cmd_enc = match device.create_command_encoder(&desc.label) {
Ok(command_buffer) => command_buffer, Ok(cmd_enc) => cmd_enc,
Err(e) => break 'error e, Err(e) => break 'error e,
}; };
let id = fid.assign(command_buffer); let id = fid.assign(cmd_enc);
api_log!("Device::create_command_encoder -> {id:?}"); api_log!("Device::create_command_encoder -> {id:?}");
return (id.into_command_encoder_id(), None); return (id, None);
}; };
let id = fid.assign(Arc::new(CommandBuffer::new_invalid( let id = fid.assign(Arc::new(CommandEncoder::new_invalid(
&device, &device,
&desc.label, &desc.label,
error.clone().into(), error.clone().into(),
))); )));
(id.into_command_encoder_id(), Some(error)) (id, Some(error))
} }
pub fn command_encoder_drop(&self, command_encoder_id: id::CommandEncoderId) { pub fn command_encoder_drop(&self, command_encoder_id: id::CommandEncoderId) {
profiling::scope!("CommandEncoder::drop"); profiling::scope!("CommandEncoder::drop");
api_log!("CommandEncoder::drop {command_encoder_id:?}"); api_log!("CommandEncoder::drop {command_encoder_id:?}");
let _cmd_enc = self.hub.command_encoders.remove(command_encoder_id);
let hub = &self.hub;
let _cmd_buf = hub
.command_buffers
.remove(command_encoder_id.into_command_buffer_id());
} }
pub fn command_buffer_drop(&self, command_buffer_id: id::CommandBufferId) { pub fn command_buffer_drop(&self, command_buffer_id: id::CommandBufferId) {
profiling::scope!("CommandBuffer::drop"); profiling::scope!("CommandBuffer::drop");
api_log!("CommandBuffer::drop {command_buffer_id:?}"); api_log!("CommandBuffer::drop {command_buffer_id:?}");
self.command_encoder_drop(command_buffer_id.into_command_encoder_id()) let _cmd_buf = self.hub.command_buffers.remove(command_buffer_id);
} }
pub fn device_create_render_bundle_encoder( pub fn device_create_render_bundle_encoder(

View File

@ -20,7 +20,7 @@ use crate::{
api_log, api_log,
command::{ command::{
extract_texture_selector, validate_linear_texture_data, validate_texture_copy_range, extract_texture_selector, validate_linear_texture_data, validate_texture_copy_range,
ClearError, CommandAllocator, CommandBuffer, CommandEncoderError, CopySide, ClearError, CommandAllocator, CommandBuffer, CommandEncoder, CommandEncoderError, CopySide,
TexelCopyTextureInfo, TransferError, TexelCopyTextureInfo, TransferError,
}, },
conv, conv,
@ -278,7 +278,7 @@ pub enum TempResource {
/// [`CommandBuffer`]: hal::Api::CommandBuffer /// [`CommandBuffer`]: hal::Api::CommandBuffer
/// [`wgpu_hal::CommandEncoder`]: hal::CommandEncoder /// [`wgpu_hal::CommandEncoder`]: hal::CommandEncoder
pub(crate) struct EncoderInFlight { pub(crate) struct EncoderInFlight {
inner: crate::command::CommandEncoder, inner: crate::command::InnerCommandEncoder,
pub(crate) trackers: Tracker, pub(crate) trackers: Tracker,
pub(crate) temp_resources: Vec<TempResource>, pub(crate) temp_resources: Vec<TempResource>,
/// We only need to keep these resources alive. /// We only need to keep these resources alive.
@ -394,12 +394,12 @@ impl PendingWrites {
.map_err(|e| device.handle_hal_error(e))?; .map_err(|e| device.handle_hal_error(e))?;
let encoder = EncoderInFlight { let encoder = EncoderInFlight {
inner: crate::command::CommandEncoder { inner: crate::command::InnerCommandEncoder {
raw: ManuallyDrop::new(mem::replace(&mut self.command_encoder, new_encoder)), raw: ManuallyDrop::new(mem::replace(&mut self.command_encoder, new_encoder)),
list: vec![cmd_buf], list: vec![cmd_buf],
device: device.clone(), device: device.clone(),
is_open: false, is_open: false,
hal_label: None, label: "(wgpu internal) PendingWrites command encoder".into(),
}, },
trackers: Tracker::new(), trackers: Tracker::new(),
temp_resources: mem::take(&mut self.temp_resources), temp_resources: mem::take(&mut self.temp_resources),
@ -1237,7 +1237,7 @@ impl Queue {
//Note: stateless trackers are not merged: //Note: stateless trackers are not merged:
// device already knows these resources exist. // device already knows these resources exist.
CommandBuffer::insert_barriers_from_device_tracker( CommandEncoder::insert_barriers_from_device_tracker(
baked.encoder.raw.as_mut(), baked.encoder.raw.as_mut(),
&mut trackers, &mut trackers,
&baked.trackers, &baked.trackers,

View File

@ -1859,7 +1859,7 @@ impl Device {
pub(crate) fn create_command_encoder( pub(crate) fn create_command_encoder(
self: &Arc<Self>, self: &Arc<Self>,
label: &crate::Label, label: &crate::Label,
) -> Result<Arc<command::CommandBuffer>, DeviceError> { ) -> Result<Arc<command::CommandEncoder>, DeviceError> {
self.check_is_valid()?; self.check_is_valid()?;
let queue = self.get_queue().unwrap(); let queue = self.get_queue().unwrap();
@ -1869,11 +1869,11 @@ impl Device {
.acquire_encoder(self.raw(), queue.raw()) .acquire_encoder(self.raw(), queue.raw())
.map_err(|e| self.handle_hal_error(e))?; .map_err(|e| self.handle_hal_error(e))?;
let command_buffer = command::CommandBuffer::new(encoder, self, label); let cmd_enc = command::CommandEncoder::new(encoder, self, label);
let command_buffer = Arc::new(command_buffer); let cmd_enc = Arc::new(cmd_enc);
Ok(command_buffer) Ok(cmd_enc)
} }
/// Generate information about late-validated buffer bindings for pipelines. /// Generate information about late-validated buffer bindings for pipelines.

View File

@ -105,7 +105,7 @@ use core::fmt::Debug;
use crate::{ use crate::{
binding_model::{BindGroup, BindGroupLayout, PipelineLayout}, binding_model::{BindGroup, BindGroupLayout, PipelineLayout},
command::{CommandBuffer, RenderBundle}, command::{CommandBuffer, CommandEncoder, RenderBundle},
device::{queue::Queue, Device}, device::{queue::Queue, Device},
instance::Adapter, instance::Adapter,
pipeline::{ComputePipeline, PipelineCache, RenderPipeline, ShaderModule}, pipeline::{ComputePipeline, PipelineCache, RenderPipeline, ShaderModule},
@ -124,6 +124,7 @@ pub struct HubReport {
pub shader_modules: RegistryReport, pub shader_modules: RegistryReport,
pub bind_group_layouts: RegistryReport, pub bind_group_layouts: RegistryReport,
pub bind_groups: RegistryReport, pub bind_groups: RegistryReport,
pub command_encoders: RegistryReport,
pub command_buffers: RegistryReport, pub command_buffers: RegistryReport,
pub render_bundles: RegistryReport, pub render_bundles: RegistryReport,
pub render_pipelines: RegistryReport, pub render_pipelines: RegistryReport,
@ -171,6 +172,7 @@ pub struct Hub {
pub(crate) shader_modules: Registry<Fallible<ShaderModule>>, pub(crate) shader_modules: Registry<Fallible<ShaderModule>>,
pub(crate) bind_group_layouts: Registry<Fallible<BindGroupLayout>>, pub(crate) bind_group_layouts: Registry<Fallible<BindGroupLayout>>,
pub(crate) bind_groups: Registry<Fallible<BindGroup>>, pub(crate) bind_groups: Registry<Fallible<BindGroup>>,
pub(crate) command_encoders: Registry<Arc<CommandEncoder>>,
pub(crate) command_buffers: Registry<Arc<CommandBuffer>>, pub(crate) command_buffers: Registry<Arc<CommandBuffer>>,
pub(crate) render_bundles: Registry<Fallible<RenderBundle>>, pub(crate) render_bundles: Registry<Fallible<RenderBundle>>,
pub(crate) render_pipelines: Registry<Fallible<RenderPipeline>>, pub(crate) render_pipelines: Registry<Fallible<RenderPipeline>>,
@ -196,6 +198,7 @@ impl Hub {
shader_modules: Registry::new(), shader_modules: Registry::new(),
bind_group_layouts: Registry::new(), bind_group_layouts: Registry::new(),
bind_groups: Registry::new(), bind_groups: Registry::new(),
command_encoders: Registry::new(),
command_buffers: Registry::new(), command_buffers: Registry::new(),
render_bundles: Registry::new(), render_bundles: Registry::new(),
render_pipelines: Registry::new(), render_pipelines: Registry::new(),
@ -221,6 +224,7 @@ impl Hub {
shader_modules: self.shader_modules.generate_report(), shader_modules: self.shader_modules.generate_report(),
bind_group_layouts: self.bind_group_layouts.generate_report(), bind_group_layouts: self.bind_group_layouts.generate_report(),
bind_groups: self.bind_groups.generate_report(), bind_groups: self.bind_groups.generate_report(),
command_encoders: self.command_encoders.generate_report(),
command_buffers: self.command_buffers.generate_report(), command_buffers: self.command_buffers.generate_report(),
render_bundles: self.render_bundles.generate_report(), render_bundles: self.render_bundles.generate_report(),
render_pipelines: self.render_pipelines.generate_report(), render_pipelines: self.render_pipelines.generate_report(),

View File

@ -280,21 +280,6 @@ ids! {
pub type TlasId Tlas; pub type TlasId Tlas;
} }
// The CommandBuffer type serves both as encoder and
// buffer, which is why the 2 functions below exist.
impl CommandEncoderId {
pub fn into_command_buffer_id(self) -> CommandBufferId {
Id(self.0, PhantomData)
}
}
impl CommandBufferId {
pub fn into_command_encoder_id(self) -> CommandEncoderId {
Id(self.0, PhantomData)
}
}
#[test] #[test]
fn test_id() { fn test_id() {
let indexes = [0, Index::MAX / 2 - 1, Index::MAX / 2 + 1, Index::MAX]; let indexes = [0, Index::MAX / 2 - 1, Index::MAX / 2 + 1, Index::MAX];

View File

@ -13,6 +13,18 @@ fn extract_marker<'a>(data: &'a [u8], range: &core::ops::Range<u32>) -> &'a str
core::str::from_utf8(&data[range.start as usize..range.end as usize]).unwrap() core::str::from_utf8(&data[range.start as usize..range.end as usize]).unwrap()
} }
fn to_debug_str(s: &str) -> &str {
// The spec mentions that if the length given to debug functions is negative,
// the implementation will access the ptr and look for a null that terminates
// the string but some implementations will try to access the ptr even if the
// length is 0.
if s.is_empty() {
"<empty>"
} else {
s
}
}
fn get_2d_target(target: u32, array_layer: u32) -> u32 { fn get_2d_target(target: u32, array_layer: u32) -> u32 {
const CUBEMAP_FACES: [u32; 6] = [ const CUBEMAP_FACES: [u32; 6] = [
glow::TEXTURE_CUBE_MAP_POSITIVE_X, glow::TEXTURE_CUBE_MAP_POSITIVE_X,
@ -1586,7 +1598,7 @@ impl super::Queue {
glow::DEBUG_TYPE_MARKER, glow::DEBUG_TYPE_MARKER,
DEBUG_ID, DEBUG_ID,
glow::DEBUG_SEVERITY_NOTIFICATION, glow::DEBUG_SEVERITY_NOTIFICATION,
marker, to_debug_str(marker),
) )
} }
}; };
@ -1599,7 +1611,11 @@ impl super::Queue {
.private_caps .private_caps
.contains(PrivateCapabilities::DEBUG_FNS) .contains(PrivateCapabilities::DEBUG_FNS)
{ {
gl.push_debug_group(glow::DEBUG_SOURCE_APPLICATION, DEBUG_ID, marker) gl.push_debug_group(
glow::DEBUG_SOURCE_APPLICATION,
DEBUG_ID,
to_debug_str(marker),
)
} }
}; };
} }
@ -1865,7 +1881,13 @@ impl crate::Queue for super::Queue {
.private_caps .private_caps
.contains(PrivateCapabilities::DEBUG_FNS) .contains(PrivateCapabilities::DEBUG_FNS)
{ {
unsafe { gl.push_debug_group(glow::DEBUG_SOURCE_APPLICATION, DEBUG_ID, label) }; unsafe {
gl.push_debug_group(
glow::DEBUG_SOURCE_APPLICATION,
DEBUG_ID,
to_debug_str(label),
)
};
} }
} }

View File

@ -580,7 +580,6 @@ pub struct CoreCommandEncoder {
pub(crate) context: ContextWgpuCore, pub(crate) context: ContextWgpuCore,
id: wgc::id::CommandEncoderId, id: wgc::id::CommandEncoderId,
error_sink: ErrorSink, error_sink: ErrorSink,
open: bool,
} }
#[derive(Debug)] #[derive(Debug)]
@ -1588,7 +1587,6 @@ impl dispatch::DeviceInterface for CoreDevice {
context: self.context.clone(), context: self.context.clone(),
id, id,
error_sink: Arc::clone(&self.error_sink), error_sink: Arc::clone(&self.error_sink),
open: true,
} }
.into() .into()
} }
@ -2390,8 +2388,10 @@ impl dispatch::CommandEncoderInterface for CoreCommandEncoder {
fn finish(&mut self) -> dispatch::DispatchCommandBuffer { fn finish(&mut self) -> dispatch::DispatchCommandBuffer {
let descriptor = wgt::CommandBufferDescriptor::default(); let descriptor = wgt::CommandBufferDescriptor::default();
self.open = false; // prevent the drop let (id, error) = self
let (id, error) = self.context.0.command_encoder_finish(self.id, &descriptor); .context
.0
.command_encoder_finish(self.id, &descriptor, None);
if let Some(cause) = error { if let Some(cause) = error {
self.context self.context
.handle_error_nolabel(&self.error_sink, cause, "a CommandEncoder"); .handle_error_nolabel(&self.error_sink, cause, "a CommandEncoder");
@ -2646,9 +2646,7 @@ impl dispatch::CommandEncoderInterface for CoreCommandEncoder {
impl Drop for CoreCommandEncoder { impl Drop for CoreCommandEncoder {
fn drop(&mut self) { fn drop(&mut self) {
if self.open { self.context.0.command_encoder_drop(self.id)
self.context.0.command_encoder_drop(self.id)
}
} }
} }