mirror of
https://github.com/gfx-rs/wgpu.git
synced 2025-12-08 21:26:17 +00:00
[wgpu-core] split command encoders from command buffers
This commit is contained in:
parent
83badd52ab
commit
63f3df86c8
@ -2,7 +2,6 @@
|
||||
|
||||
use std::borrow::Cow;
|
||||
use std::cell::RefCell;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
|
||||
use deno_core::cppgc::Ptr;
|
||||
use deno_core::op2;
|
||||
@ -29,19 +28,11 @@ pub struct GPUCommandEncoder {
|
||||
|
||||
pub id: wgpu_core::id::CommandEncoderId,
|
||||
pub label: String,
|
||||
|
||||
pub finished: AtomicBool,
|
||||
}
|
||||
|
||||
impl Drop for GPUCommandEncoder {
|
||||
fn drop(&mut self) {
|
||||
// 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);
|
||||
}
|
||||
self.instance.command_encoder_drop(self.id);
|
||||
}
|
||||
}
|
||||
|
||||
@ -416,34 +407,22 @@ impl GPUCommandEncoder {
|
||||
fn finish(
|
||||
&self,
|
||||
#[webidl] descriptor: crate::command_buffer::GPUCommandBufferDescriptor,
|
||||
) -> Result<GPUCommandBuffer, JsErrorBox> {
|
||||
) -> GPUCommandBuffer {
|
||||
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);
|
||||
.command_encoder_finish(self.id, &wgpu_descriptor, None);
|
||||
|
||||
self.error_handler.push_error(err);
|
||||
|
||||
Ok(GPUCommandBuffer {
|
||||
GPUCommandBuffer {
|
||||
instance: self.instance.clone(),
|
||||
id,
|
||||
label: descriptor.label,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn push_debug_group(&self, #[webidl] group_label: String) {
|
||||
|
||||
@ -498,7 +498,6 @@ impl GPUDevice {
|
||||
error_handler: self.error_handler.clone(),
|
||||
id,
|
||||
label,
|
||||
finished: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -7,6 +7,7 @@ fn main() {
|
||||
|
||||
use player::GlobalPlay as _;
|
||||
use wgc::device::trace;
|
||||
use wgpu_core::identity::IdentityManager;
|
||||
|
||||
use std::{
|
||||
fs,
|
||||
@ -52,7 +53,8 @@ fn main() {
|
||||
.unwrap();
|
||||
|
||||
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")]
|
||||
let surface = unsafe {
|
||||
@ -102,7 +104,14 @@ fn main() {
|
||||
unsafe { global.device_start_graphics_debugger_capture(device) };
|
||||
|
||||
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) };
|
||||
@ -164,6 +173,7 @@ fn main() {
|
||||
queue,
|
||||
action,
|
||||
&dir,
|
||||
&mut command_encoder_id_manager,
|
||||
&mut command_buffer_id_manager,
|
||||
);
|
||||
}
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
extern crate wgpu_core as wgc;
|
||||
extern crate wgpu_types as wgt;
|
||||
|
||||
use wgc::device::trace;
|
||||
use wgc::{device::trace, identity::IdentityManager};
|
||||
|
||||
use std::{borrow::Cow, fs, path::Path};
|
||||
|
||||
@ -15,6 +15,7 @@ pub trait GlobalPlay {
|
||||
&self,
|
||||
encoder: wgc::id::CommandEncoderId,
|
||||
commands: Vec<trace::Command>,
|
||||
command_buffer_id_manager: &mut IdentityManager<wgc::id::markers::CommandBuffer>,
|
||||
) -> wgc::id::CommandBufferId;
|
||||
fn process(
|
||||
&self,
|
||||
@ -22,7 +23,8 @@ pub trait GlobalPlay {
|
||||
queue: wgc::id::QueueId,
|
||||
action: trace::Action,
|
||||
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,
|
||||
encoder: wgc::id::CommandEncoderId,
|
||||
commands: Vec<trace::Command>,
|
||||
command_buffer_id_manager: &mut IdentityManager<wgc::id::markers::CommandBuffer>,
|
||||
) -> wgc::id::CommandBufferId {
|
||||
for command in commands {
|
||||
match command {
|
||||
@ -172,8 +175,11 @@ impl GlobalPlay for wgc::global::Global {
|
||||
}
|
||||
}
|
||||
}
|
||||
let (cmd_buf, error) =
|
||||
self.command_encoder_finish(encoder, &wgt::CommandBufferDescriptor { label: None });
|
||||
let (cmd_buf, error) = self.command_encoder_finish(
|
||||
encoder,
|
||||
&wgt::CommandBufferDescriptor { label: None },
|
||||
Some(command_buffer_id_manager.process()),
|
||||
);
|
||||
if let Some(e) = error {
|
||||
panic!("{e}");
|
||||
}
|
||||
@ -186,7 +192,8 @@ impl GlobalPlay for wgc::global::Global {
|
||||
queue: wgc::id::QueueId,
|
||||
action: trace::Action,
|
||||
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;
|
||||
log::debug!("action {action:?}");
|
||||
@ -379,12 +386,12 @@ impl GlobalPlay for wgc::global::Global {
|
||||
let (encoder, error) = self.device_create_command_encoder(
|
||||
device,
|
||||
&wgt::CommandEncoderDescriptor { label: None },
|
||||
Some(comb_manager.process().into_command_encoder_id()),
|
||||
Some(command_encoder_id_manager.process()),
|
||||
);
|
||||
if let Some(e) = error {
|
||||
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();
|
||||
}
|
||||
Action::CreateBlas { id, desc, sizes } => {
|
||||
|
||||
@ -20,6 +20,7 @@ use std::{
|
||||
path::{Path, PathBuf},
|
||||
slice,
|
||||
};
|
||||
use wgc::identity::IdentityManager;
|
||||
|
||||
#[derive(serde::Deserialize)]
|
||||
struct RawId {
|
||||
@ -104,7 +105,8 @@ impl Test<'_> {
|
||||
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...");
|
||||
for action in self.actions {
|
||||
global.process(
|
||||
@ -112,6 +114,7 @@ impl Test<'_> {
|
||||
queue_id,
|
||||
action,
|
||||
dir,
|
||||
&mut command_encoder_id_manager,
|
||||
&mut command_buffer_id_manager,
|
||||
);
|
||||
}
|
||||
|
||||
@ -179,7 +179,7 @@ async fn draw_test_with_reports(
|
||||
|
||||
let global_report = ctx.instance.generate_report().unwrap();
|
||||
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);
|
||||
|
||||
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.render_pipelines.num_allocated, 1);
|
||||
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.texture_views.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 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.pipeline_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.texture_views.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.pipeline_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.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 report = global_report.hub_report();
|
||||
// assert_eq!(report.command_buffers.num_allocated, 0);
|
||||
let global_report = ctx.instance.generate_report().unwrap();
|
||||
let report = global_report.hub_report();
|
||||
assert_eq!(report.command_encoders.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))
|
||||
.await
|
||||
|
||||
@ -346,7 +346,7 @@ impl Global {
|
||||
|
||||
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();
|
||||
cmd_buf_data.record_as_hal_mut(|opt_cmd_buf| -> R {
|
||||
hal_command_encoder_callback(opt_cmd_buf.and_then(|cmd_buf| {
|
||||
|
||||
@ -6,7 +6,7 @@ use crate::device::trace::Command as TraceCommand;
|
||||
use crate::{
|
||||
api_log,
|
||||
command::EncoderStateError,
|
||||
device::DeviceError,
|
||||
device::{DeviceError, MissingFeatures},
|
||||
get_lowest_common_denom,
|
||||
global::Global,
|
||||
id::{BufferId, CommandEncoderId, TextureId},
|
||||
@ -30,10 +30,10 @@ use wgt::{
|
||||
#[derive(Clone, Debug, Error)]
|
||||
#[non_exhaustive]
|
||||
pub enum ClearError {
|
||||
#[error("To use clear_texture the CLEAR_TEXTURE feature needs to be enabled")]
|
||||
MissingClearTextureFeature,
|
||||
#[error(transparent)]
|
||||
DestroyedResource(#[from] DestroyedResourceError),
|
||||
#[error(transparent)]
|
||||
MissingFeatures(#[from] MissingFeatures),
|
||||
#[error("{0} can not be cleared")]
|
||||
NoValidTextureClearMode(ResourceErrorIdent),
|
||||
#[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 {
|
||||
let e: &dyn WebGpuError = match self {
|
||||
Self::DestroyedResource(e) => e,
|
||||
Self::MissingFeatures(e) => e,
|
||||
Self::MissingBufferUsage(e) => e,
|
||||
Self::Device(e) => e,
|
||||
Self::EncoderState(e) => e,
|
||||
Self::InvalidResource(e) => e,
|
||||
Self::NoValidTextureClearMode(..)
|
||||
| Self::MissingClearTextureFeature
|
||||
| Self::UnalignedFillSize(..)
|
||||
| Self::UnalignedBufferOffset(..)
|
||||
| Self::OffsetPlusSizeExceeds64BitBounds { .. }
|
||||
@ -115,9 +115,7 @@ impl Global {
|
||||
|
||||
let hub = &self.hub;
|
||||
|
||||
let cmd_buf = hub
|
||||
.command_buffers
|
||||
.get(command_encoder_id.into_command_buffer_id());
|
||||
let cmd_buf = hub.command_encoders.get(command_encoder_id);
|
||||
let mut cmd_buf_data = cmd_buf.data.lock();
|
||||
cmd_buf_data.record_with(|cmd_buf_data| -> Result<(), ClearError> {
|
||||
#[cfg(feature = "trace")]
|
||||
@ -202,9 +200,7 @@ impl Global {
|
||||
|
||||
let hub = &self.hub;
|
||||
|
||||
let cmd_buf = hub
|
||||
.command_buffers
|
||||
.get(command_encoder_id.into_command_buffer_id());
|
||||
let cmd_buf = hub.command_encoders.get(command_encoder_id);
|
||||
let mut cmd_buf_data = cmd_buf.data.lock();
|
||||
cmd_buf_data.record_with(|cmd_buf_data| -> Result<(), ClearError> {
|
||||
#[cfg(feature = "trace")]
|
||||
@ -217,9 +213,9 @@ impl Global {
|
||||
|
||||
cmd_buf.device.check_is_valid()?;
|
||||
|
||||
if !cmd_buf.support_clear_texture {
|
||||
return Err(ClearError::MissingClearTextureFeature);
|
||||
}
|
||||
cmd_buf
|
||||
.device
|
||||
.require_features(wgt::Features::CLEAR_TEXTURE)?;
|
||||
|
||||
let dst_texture = hub.textures.get(dst).get()?;
|
||||
|
||||
|
||||
@ -7,7 +7,9 @@ use wgt::{
|
||||
use alloc::{borrow::Cow, boxed::Box, sync::Arc, vec::Vec};
|
||||
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::{binding_model::BindError, resource::RawResourceAccess};
|
||||
use crate::{
|
||||
@ -18,8 +20,8 @@ use crate::{
|
||||
end_pipeline_statistics_query,
|
||||
memory_init::{fixup_discarded_surfaces, SurfacesInDiscardState},
|
||||
pass_base, pass_try, validate_and_begin_pipeline_statistics_query, ArcPassTimestampWrites,
|
||||
BasePass, BindGroupStateChange, CommandBuffer, CommandEncoderError, MapPassErr,
|
||||
PassErrorScope, PassTimestampWrites, QueryUseError, StateChange,
|
||||
BasePass, BindGroupStateChange, CommandEncoderError, MapPassErr, PassErrorScope,
|
||||
PassTimestampWrites, QueryUseError, StateChange,
|
||||
},
|
||||
device::{DeviceError, MissingDownlevelFlags, MissingFeatures},
|
||||
global::Global,
|
||||
@ -46,12 +48,12 @@ pub struct ComputePass {
|
||||
/// All pass data & records is stored here.
|
||||
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
|
||||
/// `None`, then the pass is in the "ended" state.
|
||||
/// See <https://www.w3.org/TR/webgpu/#encoder-state>
|
||||
parent: Option<Arc<CommandBuffer>>,
|
||||
parent: Option<Arc<CommandEncoder>>,
|
||||
|
||||
timestamp_writes: Option<ArcPassTimestampWrites>,
|
||||
|
||||
@ -61,8 +63,8 @@ pub struct ComputePass {
|
||||
}
|
||||
|
||||
impl ComputePass {
|
||||
/// If the parent command buffer is invalid, the returned pass will be invalid.
|
||||
fn new(parent: Arc<CommandBuffer>, desc: ArcComputePassDescriptor) -> Self {
|
||||
/// If the parent command encoder is invalid, the returned pass will be invalid.
|
||||
fn new(parent: Arc<CommandEncoder>, desc: ArcComputePassDescriptor) -> Self {
|
||||
let ArcComputePassDescriptor {
|
||||
label,
|
||||
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 {
|
||||
base: BasePass::new_invalid(label, err),
|
||||
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,
|
||||
&mut self.intermediate_trackers,
|
||||
self.general.snatch_guard,
|
||||
@ -342,7 +344,7 @@ impl Global {
|
||||
|
||||
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();
|
||||
|
||||
match cmd_buf_data.lock_encoder() {
|
||||
@ -433,10 +435,7 @@ impl Global {
|
||||
) {
|
||||
#[cfg(feature = "trace")]
|
||||
{
|
||||
let cmd_buf = self
|
||||
.hub
|
||||
.command_buffers
|
||||
.get(encoder_id.into_command_buffer_id());
|
||||
let cmd_buf = self.hub.command_encoders.get(encoder_id);
|
||||
let mut cmd_buf_data = cmd_buf.data.lock();
|
||||
let cmd_buf_data = cmd_buf_data.get_inner();
|
||||
|
||||
@ -750,10 +749,10 @@ impl Global {
|
||||
..
|
||||
} = state;
|
||||
|
||||
// Stop the current command buffer.
|
||||
// Stop the current command encoder.
|
||||
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.
|
||||
let transit = encoder
|
||||
@ -766,13 +765,13 @@ impl Global {
|
||||
device,
|
||||
&snatch_guard,
|
||||
);
|
||||
CommandBuffer::insert_barriers_from_tracker(
|
||||
CommandEncoder::insert_barriers_from_tracker(
|
||||
transit,
|
||||
tracker,
|
||||
&intermediate_trackers,
|
||||
&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)?;
|
||||
|
||||
Ok(())
|
||||
@ -782,7 +781,7 @@ impl Global {
|
||||
|
||||
fn set_pipeline(
|
||||
state: &mut State,
|
||||
cmd_buf: &CommandBuffer,
|
||||
cmd_buf: &CommandEncoder,
|
||||
pipeline: Arc<ComputePipeline>,
|
||||
) -> Result<(), ComputePassErrorInner> {
|
||||
pipeline.same_device_as(cmd_buf)?;
|
||||
@ -859,7 +858,7 @@ fn dispatch(state: &mut State, groups: [u32; 3]) -> Result<(), ComputePassErrorI
|
||||
|
||||
fn dispatch_indirect(
|
||||
state: &mut State,
|
||||
cmd_buf: &CommandBuffer,
|
||||
cmd_buf: &CommandEncoder,
|
||||
buffer: Arc<Buffer>,
|
||||
offset: u64,
|
||||
) -> Result<(), ComputePassErrorInner> {
|
||||
|
||||
@ -145,6 +145,9 @@ impl CommandEncoderStatus {
|
||||
// Encoder is ended. Invalidate the encoder, do not record anything,
|
||||
// and return an immediate validation error.
|
||||
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
|
||||
// return an immediate validation error.
|
||||
Self::Error(_) => Ok(()),
|
||||
@ -173,6 +176,7 @@ impl CommandEncoderStatus {
|
||||
self.invalidate(EncoderStateError::Ended);
|
||||
f(None)
|
||||
}
|
||||
Self::Error(CommandEncoderError::State(EncoderStateError::Ended)) => f(None),
|
||||
Self::Error(_) => f(None),
|
||||
Self::Transitioning => unreachable!(),
|
||||
}
|
||||
@ -210,6 +214,10 @@ impl CommandEncoderStatus {
|
||||
Err(EncoderStateError::Ended)
|
||||
}
|
||||
Self::Locked(_) => Err(self.invalidate(EncoderStateError::Locked)),
|
||||
st @ Self::Error(CommandEncoderError::State(EncoderStateError::Ended)) => {
|
||||
*self = st;
|
||||
Err(EncoderStateError::Ended)
|
||||
}
|
||||
st @ Self::Error(_) => {
|
||||
*self = st;
|
||||
Err(EncoderStateError::Invalid)
|
||||
@ -254,6 +262,10 @@ impl CommandEncoderStatus {
|
||||
*self = Self::Error(EncoderStateError::Unlocked.into());
|
||||
Err(EncoderStateError::Unlocked)
|
||||
}
|
||||
st @ Self::Error(CommandEncoderError::State(EncoderStateError::Ended)) => {
|
||||
*self = st;
|
||||
Err(EncoderStateError::Ended)
|
||||
}
|
||||
st @ Self::Error(_) => {
|
||||
// Encoder is invalid. Do not record anything, but do not
|
||||
// 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.
|
||||
///
|
||||
/// 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
|
||||
/// 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
|
||||
/// [`CommandEncoder::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.
|
||||
/// [`InnerCommandEncoder::close_and_swap`] for a specific example of this.
|
||||
///
|
||||
/// [rce]: hal::Api::CommandEncoder
|
||||
/// [rcb]: hal::Api::CommandBuffer
|
||||
/// [`CommandEncoderId`]: crate::id::CommandEncoderId
|
||||
pub(crate) struct CommandEncoder {
|
||||
pub(crate) struct InnerCommandEncoder {
|
||||
/// The underlying `wgpu_hal` [`CommandEncoder`].
|
||||
///
|
||||
/// Successfully executed command buffers' encoders are saved in a
|
||||
@ -427,10 +454,10 @@ pub(crate) struct CommandEncoder {
|
||||
/// [`wgpu_hal::CommandEncoder`]: hal::CommandEncoder
|
||||
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
|
||||
/// the last element in [`self.list`][l].
|
||||
///
|
||||
@ -453,7 +480,7 @@ impl CommandEncoder {
|
||||
///
|
||||
/// - If the encoder is not open.
|
||||
///
|
||||
/// [l]: CommandEncoder::list
|
||||
/// [l]: InnerCommandEncoder::list
|
||||
/// [`transition_buffers`]: hal::CommandEncoder::transition_buffers
|
||||
/// [`transition_textures`]: hal::CommandEncoder::transition_textures
|
||||
fn close_and_swap(&mut self) -> Result<(), DeviceError> {
|
||||
@ -476,7 +503,7 @@ impl CommandEncoder {
|
||||
///
|
||||
/// - If the encoder is not open.
|
||||
///
|
||||
/// [l]: CommandEncoder::list
|
||||
/// [l]: InnerCommandEncoder::list
|
||||
pub(crate) fn close_and_push_front(&mut self) -> Result<(), DeviceError> {
|
||||
assert!(self.is_open);
|
||||
self.is_open = false;
|
||||
@ -497,7 +524,7 @@ impl CommandEncoder {
|
||||
///
|
||||
/// - If the encoder is not open.
|
||||
///
|
||||
/// [l]: CommandEncoder::list
|
||||
/// [l]: InnerCommandEncoder::list
|
||||
pub(crate) fn close(&mut self) -> Result<(), DeviceError> {
|
||||
assert!(self.is_open);
|
||||
self.is_open = false;
|
||||
@ -518,7 +545,7 @@ impl CommandEncoder {
|
||||
///
|
||||
/// On return, the underlying hal encoder is closed.
|
||||
///
|
||||
/// [l]: CommandEncoder::list
|
||||
/// [l]: InnerCommandEncoder::list
|
||||
fn close_if_open(&mut self) -> Result<(), DeviceError> {
|
||||
if self.is_open {
|
||||
self.is_open = false;
|
||||
@ -536,7 +563,7 @@ impl CommandEncoder {
|
||||
pub(crate) fn open(&mut self) -> Result<&mut dyn hal::DynCommandEncoder, DeviceError> {
|
||||
if !self.is_open {
|
||||
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) }
|
||||
.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) {
|
||||
if self.is_open {
|
||||
unsafe { self.raw.discard_encoding() };
|
||||
@ -584,7 +611,7 @@ impl Drop for CommandEncoder {
|
||||
/// Look at the documentation for [`CommandBufferMutable`] for an explanation of
|
||||
/// the fields in this struct. This is the "built" counterpart to that type.
|
||||
pub(crate) struct BakedCommands {
|
||||
pub(crate) encoder: CommandEncoder,
|
||||
pub(crate) encoder: InnerCommandEncoder,
|
||||
pub(crate) trackers: Tracker,
|
||||
pub(crate) temp_resources: Vec<TempResource>,
|
||||
pub(crate) indirect_draw_validation_resources: crate::indirect_validation::DrawResources,
|
||||
@ -598,7 +625,7 @@ pub struct CommandBufferMutable {
|
||||
/// they belong to.
|
||||
///
|
||||
/// [`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.
|
||||
pub(crate) trackers: Tracker,
|
||||
@ -647,25 +674,11 @@ impl CommandBufferMutable {
|
||||
|
||||
/// A buffer of commands to be submitted to the GPU for execution.
|
||||
///
|
||||
/// Whereas the WebGPU API uses two separate types for command buffers and
|
||||
/// encoders, this type is a fusion of the two:
|
||||
///
|
||||
/// - 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.
|
||||
/// Once a command buffer is submitted to the queue, its contents are taken
|
||||
/// to construct a [`BakedCommands`], whose contents eventually become the
|
||||
/// property of the submission queue.
|
||||
pub struct CommandBuffer {
|
||||
pub(crate) device: Arc<Device>,
|
||||
support_clear_texture: bool,
|
||||
/// The `label` from the descriptor used to create the resource.
|
||||
label: String,
|
||||
|
||||
@ -679,25 +692,24 @@ impl Drop for CommandBuffer {
|
||||
}
|
||||
}
|
||||
|
||||
impl CommandBuffer {
|
||||
impl CommandEncoder {
|
||||
pub(crate) fn new(
|
||||
encoder: Box<dyn hal::DynCommandEncoder>,
|
||||
device: &Arc<Device>,
|
||||
label: &Label,
|
||||
) -> Self {
|
||||
CommandBuffer {
|
||||
CommandEncoder {
|
||||
device: device.clone(),
|
||||
support_clear_texture: device.features.contains(wgt::Features::CLEAR_TEXTURE),
|
||||
label: label.to_string(),
|
||||
data: Mutex::new(
|
||||
rank::COMMAND_BUFFER_DATA,
|
||||
CommandEncoderStatus::Recording(CommandBufferMutable {
|
||||
encoder: CommandEncoder {
|
||||
encoder: InnerCommandEncoder {
|
||||
raw: ManuallyDrop::new(encoder),
|
||||
list: Vec::new(),
|
||||
device: device.clone(),
|
||||
is_open: false,
|
||||
hal_label: label.to_hal(device.instance_flags).map(str::to_owned),
|
||||
label: label.to_string(),
|
||||
},
|
||||
trackers: Tracker::new(),
|
||||
buffer_memory_init_actions: Default::default(),
|
||||
@ -723,9 +735,8 @@ impl CommandBuffer {
|
||||
label: &Label,
|
||||
err: CommandEncoderError,
|
||||
) -> Self {
|
||||
CommandBuffer {
|
||||
CommandEncoder {
|
||||
device: device.clone(),
|
||||
support_clear_texture: device.features.contains(wgt::Features::CLEAR_TEXTURE),
|
||||
label: label.to_string(),
|
||||
data: Mutex::new(rank::COMMAND_BUFFER_DATA, CommandEncoderStatus::Error(err)),
|
||||
}
|
||||
@ -1123,22 +1134,40 @@ impl Global {
|
||||
pub fn command_encoder_finish(
|
||||
&self,
|
||||
encoder_id: id::CommandEncoderId,
|
||||
_desc: &wgt::CommandBufferDescriptor<Label>,
|
||||
desc: &wgt::CommandBufferDescriptor<Label>,
|
||||
id_in: Option<id::CommandBufferId>,
|
||||
) -> (id::CommandBufferId, Option<CommandEncoderError>) {
|
||||
profiling::scope!("CommandEncoder::finish");
|
||||
|
||||
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
|
||||
// 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),
|
||||
_ => 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(
|
||||
@ -1151,7 +1180,7 @@ impl Global {
|
||||
|
||||
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();
|
||||
cmd_buf_data.record_with(|cmd_buf_data| -> Result<(), CommandEncoderError> {
|
||||
#[cfg(feature = "trace")]
|
||||
@ -1186,7 +1215,7 @@ impl Global {
|
||||
|
||||
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();
|
||||
cmd_buf_data.record_with(|cmd_buf_data| -> Result<(), CommandEncoderError> {
|
||||
#[cfg(feature = "trace")]
|
||||
@ -1220,7 +1249,7 @@ impl Global {
|
||||
|
||||
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();
|
||||
cmd_buf_data.record_with(|cmd_buf_data| -> Result<(), CommandEncoderError> {
|
||||
#[cfg(feature = "trace")]
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
use crate::binding_model::{BindError, BindGroup, PushConstantUploadError};
|
||||
use crate::command::bind::Binder;
|
||||
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::init_tracker::BufferInitTrackerAction;
|
||||
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>(
|
||||
state: &mut BaseState,
|
||||
cmd_buf: &CommandBuffer,
|
||||
cmd_buf: &CommandEncoder,
|
||||
dynamic_offsets: &[DynamicOffset],
|
||||
index: u32,
|
||||
num_dynamic_offsets: usize,
|
||||
@ -287,7 +287,7 @@ where
|
||||
|
||||
pub(crate) fn write_timestamp<E>(
|
||||
state: &mut BaseState,
|
||||
cmd_buf: &CommandBuffer,
|
||||
cmd_buf: &CommandEncoder,
|
||||
pending_query_resets: Option<&mut QueryResetMap>,
|
||||
query_set: Arc<QuerySet>,
|
||||
query_index: u32,
|
||||
|
||||
@ -4,7 +4,7 @@ use core::{iter, mem};
|
||||
#[cfg(feature = "trace")]
|
||||
use crate::device::trace::Command as TraceCommand;
|
||||
use crate::{
|
||||
command::{CommandBuffer, EncoderStateError},
|
||||
command::{CommandEncoder, EncoderStateError},
|
||||
device::{DeviceError, MissingFeatures},
|
||||
global::Global,
|
||||
id,
|
||||
@ -307,7 +307,7 @@ pub(super) fn validate_and_begin_pipeline_statistics_query(
|
||||
query_set: Arc<QuerySet>,
|
||||
raw_encoder: &mut dyn hal::DynCommandEncoder,
|
||||
tracker: &mut StatelessTracker<QuerySet>,
|
||||
cmd_buf: &CommandBuffer,
|
||||
cmd_buf: &CommandEncoder,
|
||||
query_index: u32,
|
||||
reset_state: Option<&mut QueryResetMap>,
|
||||
active_query: &mut Option<(Arc<QuerySet>, u32)>,
|
||||
@ -363,9 +363,7 @@ impl Global {
|
||||
) -> Result<(), EncoderStateError> {
|
||||
let hub = &self.hub;
|
||||
|
||||
let cmd_buf = hub
|
||||
.command_buffers
|
||||
.get(command_encoder_id.into_command_buffer_id());
|
||||
let cmd_buf = hub.command_encoders.get(command_encoder_id);
|
||||
let mut cmd_buf_data = cmd_buf.data.lock();
|
||||
cmd_buf_data.record_with(|cmd_buf_data| -> Result<(), QueryError> {
|
||||
#[cfg(feature = "trace")]
|
||||
@ -406,9 +404,7 @@ impl Global {
|
||||
) -> Result<(), EncoderStateError> {
|
||||
let hub = &self.hub;
|
||||
|
||||
let cmd_buf = hub
|
||||
.command_buffers
|
||||
.get(command_encoder_id.into_command_buffer_id());
|
||||
let cmd_buf = hub.command_encoders.get(command_encoder_id);
|
||||
let mut cmd_buf_data = cmd_buf.data.lock();
|
||||
cmd_buf_data.record_with(|cmd_buf_data| -> Result<(), QueryError> {
|
||||
#[cfg(feature = "trace")]
|
||||
|
||||
@ -67,9 +67,7 @@ impl Global {
|
||||
|
||||
let hub = &self.hub;
|
||||
|
||||
let cmd_buf = hub
|
||||
.command_buffers
|
||||
.get(command_encoder_id.into_command_buffer_id());
|
||||
let cmd_buf = hub.command_encoders.get(command_encoder_id);
|
||||
|
||||
let mut cmd_buf_data = cmd_buf.data.lock();
|
||||
cmd_buf_data.record_with(
|
||||
@ -109,9 +107,7 @@ impl Global {
|
||||
|
||||
let hub = &self.hub;
|
||||
|
||||
let cmd_buf = hub
|
||||
.command_buffers
|
||||
.get(command_encoder_id.into_command_buffer_id());
|
||||
let cmd_buf = hub.command_encoders.get(command_encoder_id);
|
||||
|
||||
let mut build_command = AsBuild::default();
|
||||
|
||||
|
||||
@ -11,8 +11,8 @@ use wgt::{
|
||||
|
||||
use crate::command::{
|
||||
pass, pass_base, pass_try, validate_and_begin_occlusion_query,
|
||||
validate_and_begin_pipeline_statistics_query, EncoderStateError, PassStateError,
|
||||
TimestampWritesError,
|
||||
validate_and_begin_pipeline_statistics_query, EncoderStateError, InnerCommandEncoder,
|
||||
PassStateError, TimestampWritesError,
|
||||
};
|
||||
use crate::pipeline::{RenderPipeline, VertexStep};
|
||||
use crate::resource::RawResourceAccess;
|
||||
@ -24,8 +24,8 @@ use crate::{
|
||||
bind::Binder,
|
||||
end_occlusion_query, end_pipeline_statistics_query,
|
||||
memory_init::{fixup_discarded_surfaces, SurfacesInDiscardState},
|
||||
ArcPassTimestampWrites, BasePass, BindGroupStateChange, CommandBuffer, CommandEncoderError,
|
||||
DrawError, ExecutionError, MapPassErr, PassErrorScope, PassTimestampWrites, QueryUseError,
|
||||
ArcPassTimestampWrites, BasePass, BindGroupStateChange, CommandEncoderError, DrawError,
|
||||
ExecutionError, MapPassErr, PassErrorScope, PassTimestampWrites, QueryUseError,
|
||||
RenderCommandError, StateChange,
|
||||
},
|
||||
device::{
|
||||
@ -258,12 +258,12 @@ pub struct RenderPass {
|
||||
/// All pass data & records is stored here.
|
||||
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
|
||||
/// `None`, then the pass is in the "ended" state.
|
||||
/// See <https://www.w3.org/TR/webgpu/#encoder-state>
|
||||
parent: Option<Arc<CommandBuffer>>,
|
||||
parent: Option<Arc<CommandEncoder>>,
|
||||
|
||||
color_attachments:
|
||||
ArrayVec<Option<ArcRenderPassColorAttachment>, { hal::MAX_COLOR_ATTACHMENTS }>,
|
||||
@ -277,8 +277,8 @@ pub struct RenderPass {
|
||||
}
|
||||
|
||||
impl RenderPass {
|
||||
/// If the parent command buffer is invalid, the returned pass will be invalid.
|
||||
fn new(parent: Arc<CommandBuffer>, desc: ArcRenderPassDescriptor) -> Self {
|
||||
/// If the parent command encoder is invalid, the returned pass will be invalid.
|
||||
fn new(parent: Arc<CommandEncoder>, desc: ArcRenderPassDescriptor) -> Self {
|
||||
let ArcRenderPassDescriptor {
|
||||
label,
|
||||
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 {
|
||||
base: BasePass::new_invalid(label, err),
|
||||
parent: Some(parent),
|
||||
@ -955,7 +955,7 @@ impl RenderPassInfo {
|
||||
mut depth_stencil_attachment: Option<ArcRenderPassDepthStencilAttachment>,
|
||||
mut timestamp_writes: Option<ArcPassTimestampWrites>,
|
||||
mut occlusion_query_set: Option<Arc<QuerySet>>,
|
||||
encoder: &mut CommandEncoder,
|
||||
encoder: &mut InnerCommandEncoder,
|
||||
trackers: &mut Tracker,
|
||||
texture_memory_actions: &mut CommandBufferTextureMemoryActions,
|
||||
pending_query_resets: &mut QueryResetMap,
|
||||
@ -1665,7 +1665,7 @@ impl Global {
|
||||
let scope = PassErrorScope::Pass;
|
||||
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();
|
||||
|
||||
match cmd_buf_data.lock_encoder() {
|
||||
@ -1739,10 +1739,7 @@ impl Global {
|
||||
) {
|
||||
#[cfg(feature = "trace")]
|
||||
{
|
||||
let cmd_buf = self
|
||||
.hub
|
||||
.command_buffers
|
||||
.get(encoder_id.into_command_buffer_id());
|
||||
let cmd_buf = self.hub.command_encoders.get(encoder_id);
|
||||
let mut cmd_buf_data = cmd_buf.data.lock();
|
||||
let cmd_buf_data = cmd_buf_data.get_inner();
|
||||
|
||||
@ -2233,7 +2230,7 @@ impl Global {
|
||||
|
||||
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 {
|
||||
indirect_validation
|
||||
@ -2259,7 +2256,7 @@ impl Global {
|
||||
|
||||
fn set_pipeline(
|
||||
state: &mut State,
|
||||
cmd_buf: &Arc<CommandBuffer>,
|
||||
cmd_buf: &Arc<CommandEncoder>,
|
||||
pipeline: Arc<RenderPipeline>,
|
||||
) -> Result<(), RenderPassErrorInner> {
|
||||
api_log!("RenderPass::set_pipeline {}", pipeline.error_ident());
|
||||
@ -2326,7 +2323,7 @@ fn set_pipeline(
|
||||
// This function is duplicative of `bundle::set_index_buffer`.
|
||||
fn set_index_buffer(
|
||||
state: &mut State,
|
||||
cmd_buf: &Arc<CommandBuffer>,
|
||||
cmd_buf: &Arc<CommandEncoder>,
|
||||
buffer: Arc<crate::resource::Buffer>,
|
||||
index_format: IndexFormat,
|
||||
offset: u64,
|
||||
@ -2374,7 +2371,7 @@ fn set_index_buffer(
|
||||
// This function is duplicative of `render::set_vertex_buffer`.
|
||||
fn set_vertex_buffer(
|
||||
state: &mut State,
|
||||
cmd_buf: &Arc<CommandBuffer>,
|
||||
cmd_buf: &Arc<CommandEncoder>,
|
||||
slot: u32,
|
||||
buffer: Arc<crate::resource::Buffer>,
|
||||
offset: u64,
|
||||
@ -2607,7 +2604,7 @@ fn multi_draw_indirect(
|
||||
state: &mut State,
|
||||
indirect_draw_validation_resources: &mut crate::indirect_validation::DrawResources,
|
||||
indirect_draw_validation_batcher: &mut crate::indirect_validation::DrawBatcher,
|
||||
cmd_buf: &Arc<CommandBuffer>,
|
||||
cmd_buf: &Arc<CommandEncoder>,
|
||||
indirect_buffer: Arc<crate::resource::Buffer>,
|
||||
offset: u64,
|
||||
count: u32,
|
||||
@ -2788,7 +2785,7 @@ fn multi_draw_indirect(
|
||||
|
||||
fn multi_draw_indirect_count(
|
||||
state: &mut State,
|
||||
cmd_buf: &Arc<CommandBuffer>,
|
||||
cmd_buf: &Arc<CommandEncoder>,
|
||||
indirect_buffer: Arc<crate::resource::Buffer>,
|
||||
offset: u64,
|
||||
count_buffer: Arc<crate::resource::Buffer>,
|
||||
@ -2901,7 +2898,7 @@ fn execute_bundle(
|
||||
state: &mut State,
|
||||
indirect_draw_validation_resources: &mut crate::indirect_validation::DrawResources,
|
||||
indirect_draw_validation_batcher: &mut crate::indirect_validation::DrawBatcher,
|
||||
cmd_buf: &Arc<CommandBuffer>,
|
||||
cmd_buf: &Arc<CommandEncoder>,
|
||||
bundle: Arc<super::RenderBundle>,
|
||||
) -> Result<(), RenderPassErrorInner> {
|
||||
api_log!("RenderPass::execute_bundle {}", bundle.error_ident());
|
||||
|
||||
@ -640,9 +640,7 @@ impl Global {
|
||||
|
||||
let hub = &self.hub;
|
||||
|
||||
let cmd_buf = hub
|
||||
.command_buffers
|
||||
.get(command_encoder_id.into_command_buffer_id());
|
||||
let cmd_buf = hub.command_encoders.get(command_encoder_id);
|
||||
let mut cmd_buf_data = cmd_buf.data.lock();
|
||||
cmd_buf_data.record_with(|cmd_buf_data| -> Result<(), CommandEncoderError> {
|
||||
let device = &cmd_buf.device;
|
||||
@ -809,9 +807,7 @@ impl Global {
|
||||
|
||||
let hub = &self.hub;
|
||||
|
||||
let cmd_buf = hub
|
||||
.command_buffers
|
||||
.get(command_encoder_id.into_command_buffer_id());
|
||||
let cmd_buf = hub.command_encoders.get(command_encoder_id);
|
||||
let mut cmd_buf_data = cmd_buf.data.lock();
|
||||
cmd_buf_data.record_with(|cmd_buf_data| -> Result<(), CommandEncoderError> {
|
||||
let device = &cmd_buf.device;
|
||||
@ -967,9 +963,7 @@ impl Global {
|
||||
|
||||
let hub = &self.hub;
|
||||
|
||||
let cmd_buf = hub
|
||||
.command_buffers
|
||||
.get(command_encoder_id.into_command_buffer_id());
|
||||
let cmd_buf = hub.command_encoders.get(command_encoder_id);
|
||||
let mut cmd_buf_data = cmd_buf.data.lock();
|
||||
cmd_buf_data.record_with(|cmd_buf_data| -> Result<(), CommandEncoderError> {
|
||||
let device = &cmd_buf.device;
|
||||
@ -1142,9 +1136,7 @@ impl Global {
|
||||
|
||||
let hub = &self.hub;
|
||||
|
||||
let cmd_buf = hub
|
||||
.command_buffers
|
||||
.get(command_encoder_id.into_command_buffer_id());
|
||||
let cmd_buf = hub.command_encoders.get(command_encoder_id);
|
||||
let mut cmd_buf_data = cmd_buf.data.lock();
|
||||
cmd_buf_data.record_with(|cmd_buf_data| -> Result<(), CommandEncoderError> {
|
||||
let device = &cmd_buf.device;
|
||||
|
||||
@ -2,7 +2,7 @@ use thiserror::Error;
|
||||
use wgt::error::{ErrorType, WebGpuError};
|
||||
|
||||
use crate::{
|
||||
command::{CommandBuffer, CommandEncoderError, EncoderStateError},
|
||||
command::{CommandEncoder, CommandEncoderError, EncoderStateError},
|
||||
device::DeviceError,
|
||||
global::Global,
|
||||
id::{BufferId, CommandEncoderId, TextureId},
|
||||
@ -22,9 +22,7 @@ impl Global {
|
||||
let hub = &self.hub;
|
||||
|
||||
// Lock command encoder for recording
|
||||
let cmd_buf = hub
|
||||
.command_buffers
|
||||
.get(command_encoder_id.into_command_buffer_id());
|
||||
let cmd_buf = hub.command_encoders.get(command_encoder_id);
|
||||
let mut cmd_buf_data = cmd_buf.data.lock();
|
||||
cmd_buf_data.record_with(|cmd_buf_data| -> Result<(), CommandEncoderError> {
|
||||
// Get and lock device
|
||||
@ -63,7 +61,7 @@ impl Global {
|
||||
|
||||
// Record any needed barriers based on tracker data
|
||||
let cmd_buf_raw = cmd_buf_data.encoder.open()?;
|
||||
CommandBuffer::insert_barriers_from_scope(
|
||||
CommandEncoder::insert_barriers_from_scope(
|
||||
cmd_buf_raw,
|
||||
&mut cmd_buf_data.trackers,
|
||||
&usage_scope,
|
||||
|
||||
@ -9,7 +9,7 @@ use crate::{
|
||||
self, BindGroupEntry, BindingResource, BufferBinding, ResolvedBindGroupDescriptor,
|
||||
ResolvedBindGroupEntry, ResolvedBindingResource, ResolvedBufferBinding,
|
||||
},
|
||||
command::{self, CommandBuffer},
|
||||
command::{self, CommandEncoder},
|
||||
conv,
|
||||
device::{bgl, life::WaitIdleError, DeviceError, DeviceLostClosure},
|
||||
global::Global,
|
||||
@ -1051,46 +1051,39 @@ impl Global {
|
||||
profiling::scope!("Device::create_command_encoder");
|
||||
|
||||
let hub = &self.hub;
|
||||
let fid = hub
|
||||
.command_buffers
|
||||
.prepare(id_in.map(|id| id.into_command_buffer_id()));
|
||||
let fid = hub.command_encoders.prepare(id_in);
|
||||
|
||||
let device = self.hub.devices.get(device_id);
|
||||
|
||||
let error = 'error: {
|
||||
let command_buffer = match device.create_command_encoder(&desc.label) {
|
||||
Ok(command_buffer) => command_buffer,
|
||||
let cmd_enc = match device.create_command_encoder(&desc.label) {
|
||||
Ok(cmd_enc) => cmd_enc,
|
||||
Err(e) => break 'error e,
|
||||
};
|
||||
|
||||
let id = fid.assign(command_buffer);
|
||||
let id = fid.assign(cmd_enc);
|
||||
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,
|
||||
&desc.label,
|
||||
error.clone().into(),
|
||||
)));
|
||||
(id.into_command_encoder_id(), Some(error))
|
||||
(id, Some(error))
|
||||
}
|
||||
|
||||
pub fn command_encoder_drop(&self, command_encoder_id: id::CommandEncoderId) {
|
||||
profiling::scope!("CommandEncoder::drop");
|
||||
api_log!("CommandEncoder::drop {command_encoder_id:?}");
|
||||
|
||||
let hub = &self.hub;
|
||||
|
||||
let _cmd_buf = hub
|
||||
.command_buffers
|
||||
.remove(command_encoder_id.into_command_buffer_id());
|
||||
let _cmd_enc = self.hub.command_encoders.remove(command_encoder_id);
|
||||
}
|
||||
|
||||
pub fn command_buffer_drop(&self, command_buffer_id: id::CommandBufferId) {
|
||||
profiling::scope!("CommandBuffer::drop");
|
||||
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(
|
||||
|
||||
@ -20,7 +20,7 @@ use crate::{
|
||||
api_log,
|
||||
command::{
|
||||
extract_texture_selector, validate_linear_texture_data, validate_texture_copy_range,
|
||||
ClearError, CommandAllocator, CommandBuffer, CommandEncoderError, CopySide,
|
||||
ClearError, CommandAllocator, CommandBuffer, CommandEncoder, CommandEncoderError, CopySide,
|
||||
TexelCopyTextureInfo, TransferError,
|
||||
},
|
||||
conv,
|
||||
@ -278,7 +278,7 @@ pub enum TempResource {
|
||||
/// [`CommandBuffer`]: hal::Api::CommandBuffer
|
||||
/// [`wgpu_hal::CommandEncoder`]: hal::CommandEncoder
|
||||
pub(crate) struct EncoderInFlight {
|
||||
inner: crate::command::CommandEncoder,
|
||||
inner: crate::command::InnerCommandEncoder,
|
||||
pub(crate) trackers: Tracker,
|
||||
pub(crate) temp_resources: Vec<TempResource>,
|
||||
/// We only need to keep these resources alive.
|
||||
@ -394,12 +394,12 @@ impl PendingWrites {
|
||||
.map_err(|e| device.handle_hal_error(e))?;
|
||||
|
||||
let encoder = EncoderInFlight {
|
||||
inner: crate::command::CommandEncoder {
|
||||
inner: crate::command::InnerCommandEncoder {
|
||||
raw: ManuallyDrop::new(mem::replace(&mut self.command_encoder, new_encoder)),
|
||||
list: vec![cmd_buf],
|
||||
device: device.clone(),
|
||||
is_open: false,
|
||||
hal_label: None,
|
||||
label: "(wgpu internal) PendingWrites command encoder".into(),
|
||||
},
|
||||
trackers: Tracker::new(),
|
||||
temp_resources: mem::take(&mut self.temp_resources),
|
||||
@ -1237,7 +1237,7 @@ impl Queue {
|
||||
|
||||
//Note: stateless trackers are not merged:
|
||||
// device already knows these resources exist.
|
||||
CommandBuffer::insert_barriers_from_device_tracker(
|
||||
CommandEncoder::insert_barriers_from_device_tracker(
|
||||
baked.encoder.raw.as_mut(),
|
||||
&mut trackers,
|
||||
&baked.trackers,
|
||||
|
||||
@ -1859,7 +1859,7 @@ impl Device {
|
||||
pub(crate) fn create_command_encoder(
|
||||
self: &Arc<Self>,
|
||||
label: &crate::Label,
|
||||
) -> Result<Arc<command::CommandBuffer>, DeviceError> {
|
||||
) -> Result<Arc<command::CommandEncoder>, DeviceError> {
|
||||
self.check_is_valid()?;
|
||||
|
||||
let queue = self.get_queue().unwrap();
|
||||
@ -1869,11 +1869,11 @@ impl Device {
|
||||
.acquire_encoder(self.raw(), queue.raw())
|
||||
.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.
|
||||
|
||||
@ -105,7 +105,7 @@ use core::fmt::Debug;
|
||||
|
||||
use crate::{
|
||||
binding_model::{BindGroup, BindGroupLayout, PipelineLayout},
|
||||
command::{CommandBuffer, RenderBundle},
|
||||
command::{CommandBuffer, CommandEncoder, RenderBundle},
|
||||
device::{queue::Queue, Device},
|
||||
instance::Adapter,
|
||||
pipeline::{ComputePipeline, PipelineCache, RenderPipeline, ShaderModule},
|
||||
@ -124,6 +124,7 @@ pub struct HubReport {
|
||||
pub shader_modules: RegistryReport,
|
||||
pub bind_group_layouts: RegistryReport,
|
||||
pub bind_groups: RegistryReport,
|
||||
pub command_encoders: RegistryReport,
|
||||
pub command_buffers: RegistryReport,
|
||||
pub render_bundles: RegistryReport,
|
||||
pub render_pipelines: RegistryReport,
|
||||
@ -171,6 +172,7 @@ pub struct Hub {
|
||||
pub(crate) shader_modules: Registry<Fallible<ShaderModule>>,
|
||||
pub(crate) bind_group_layouts: Registry<Fallible<BindGroupLayout>>,
|
||||
pub(crate) bind_groups: Registry<Fallible<BindGroup>>,
|
||||
pub(crate) command_encoders: Registry<Arc<CommandEncoder>>,
|
||||
pub(crate) command_buffers: Registry<Arc<CommandBuffer>>,
|
||||
pub(crate) render_bundles: Registry<Fallible<RenderBundle>>,
|
||||
pub(crate) render_pipelines: Registry<Fallible<RenderPipeline>>,
|
||||
@ -196,6 +198,7 @@ impl Hub {
|
||||
shader_modules: Registry::new(),
|
||||
bind_group_layouts: Registry::new(),
|
||||
bind_groups: Registry::new(),
|
||||
command_encoders: Registry::new(),
|
||||
command_buffers: Registry::new(),
|
||||
render_bundles: Registry::new(),
|
||||
render_pipelines: Registry::new(),
|
||||
@ -221,6 +224,7 @@ impl Hub {
|
||||
shader_modules: self.shader_modules.generate_report(),
|
||||
bind_group_layouts: self.bind_group_layouts.generate_report(),
|
||||
bind_groups: self.bind_groups.generate_report(),
|
||||
command_encoders: self.command_encoders.generate_report(),
|
||||
command_buffers: self.command_buffers.generate_report(),
|
||||
render_bundles: self.render_bundles.generate_report(),
|
||||
render_pipelines: self.render_pipelines.generate_report(),
|
||||
|
||||
@ -280,21 +280,6 @@ ids! {
|
||||
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]
|
||||
fn test_id() {
|
||||
let indexes = [0, Index::MAX / 2 - 1, Index::MAX / 2 + 1, Index::MAX];
|
||||
|
||||
@ -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()
|
||||
}
|
||||
|
||||
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 {
|
||||
const CUBEMAP_FACES: [u32; 6] = [
|
||||
glow::TEXTURE_CUBE_MAP_POSITIVE_X,
|
||||
@ -1586,7 +1598,7 @@ impl super::Queue {
|
||||
glow::DEBUG_TYPE_MARKER,
|
||||
DEBUG_ID,
|
||||
glow::DEBUG_SEVERITY_NOTIFICATION,
|
||||
marker,
|
||||
to_debug_str(marker),
|
||||
)
|
||||
}
|
||||
};
|
||||
@ -1599,7 +1611,11 @@ impl super::Queue {
|
||||
.private_caps
|
||||
.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
|
||||
.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),
|
||||
)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -580,7 +580,6 @@ pub struct CoreCommandEncoder {
|
||||
pub(crate) context: ContextWgpuCore,
|
||||
id: wgc::id::CommandEncoderId,
|
||||
error_sink: ErrorSink,
|
||||
open: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@ -1588,7 +1587,6 @@ impl dispatch::DeviceInterface for CoreDevice {
|
||||
context: self.context.clone(),
|
||||
id,
|
||||
error_sink: Arc::clone(&self.error_sink),
|
||||
open: true,
|
||||
}
|
||||
.into()
|
||||
}
|
||||
@ -2390,8 +2388,10 @@ impl dispatch::CommandEncoderInterface for CoreCommandEncoder {
|
||||
|
||||
fn finish(&mut self) -> dispatch::DispatchCommandBuffer {
|
||||
let descriptor = wgt::CommandBufferDescriptor::default();
|
||||
self.open = false; // prevent the drop
|
||||
let (id, error) = self.context.0.command_encoder_finish(self.id, &descriptor);
|
||||
let (id, error) = self
|
||||
.context
|
||||
.0
|
||||
.command_encoder_finish(self.id, &descriptor, None);
|
||||
if let Some(cause) = error {
|
||||
self.context
|
||||
.handle_error_nolabel(&self.error_sink, cause, "a CommandEncoder");
|
||||
@ -2646,9 +2646,7 @@ impl dispatch::CommandEncoderInterface for CoreCommandEncoder {
|
||||
|
||||
impl Drop for CoreCommandEncoder {
|
||||
fn drop(&mut self) {
|
||||
if self.open {
|
||||
self.context.0.command_encoder_drop(self.id)
|
||||
}
|
||||
self.context.0.command_encoder_drop(self.id)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user