mirror of
https://github.com/gfx-rs/wgpu.git
synced 2024-11-25 08:13:27 +00:00
move CommandEncoderStatus
on the CommandBuffer
and change its variants to hold CommandBufferMutable
This makes the code more straightforward, we were previously holding invalidity state in 2 places: `CommandBuffer::data` could hold `None` and in `CommandEncoderStatus::Error`. This commit also implements `Drop` for `CommandEncoder` which makes the destruction/reclamation code automatic. We were previously not reclaiming all command encoders (`CommandBufferMutable::destroy` didn't call `release_encoder`) even though all encoders are coming from a pool.
This commit is contained in:
parent
144c47680f
commit
349ff853d1
@ -91,8 +91,8 @@ impl Global {
|
||||
let cmd_buf = hub
|
||||
.command_buffers
|
||||
.get(command_encoder_id.into_command_buffer_id());
|
||||
let mut cmd_buf_data = cmd_buf.try_get()?;
|
||||
cmd_buf_data.check_recording()?;
|
||||
let mut cmd_buf_data = cmd_buf.data.lock();
|
||||
let cmd_buf_data = cmd_buf_data.record()?;
|
||||
|
||||
#[cfg(feature = "trace")]
|
||||
if let Some(ref mut list) = cmd_buf_data.commands {
|
||||
@ -174,8 +174,8 @@ impl Global {
|
||||
let cmd_buf = hub
|
||||
.command_buffers
|
||||
.get(command_encoder_id.into_command_buffer_id());
|
||||
let mut cmd_buf_data = cmd_buf.try_get()?;
|
||||
cmd_buf_data.check_recording()?;
|
||||
let mut cmd_buf_data = cmd_buf.data.lock();
|
||||
let cmd_buf_data = cmd_buf_data.record()?;
|
||||
|
||||
#[cfg(feature = "trace")]
|
||||
if let Some(ref mut list) = cmd_buf_data.commands {
|
||||
|
@ -8,8 +8,8 @@ use crate::{
|
||||
end_pipeline_statistics_query,
|
||||
memory_init::{fixup_discarded_surfaces, SurfacesInDiscardState},
|
||||
validate_and_begin_pipeline_statistics_query, ArcPassTimestampWrites, BasePass,
|
||||
BindGroupStateChange, CommandBuffer, CommandEncoderError, CommandEncoderStatus, MapPassErr,
|
||||
PassErrorScope, PassTimestampWrites, QueryUseError, StateChange,
|
||||
BindGroupStateChange, CommandBuffer, CommandEncoderError, MapPassErr, PassErrorScope,
|
||||
PassTimestampWrites, QueryUseError, StateChange,
|
||||
},
|
||||
device::{Device, DeviceError, MissingDownlevelFlags, MissingFeatures},
|
||||
global::Global,
|
||||
@ -30,8 +30,7 @@ use wgt::{BufferAddress, DynamicOffset};
|
||||
|
||||
use super::{bind::BinderError, memory_init::CommandBufferTextureMemoryActions};
|
||||
use crate::ray_tracing::TlasAction;
|
||||
use std::sync::Arc;
|
||||
use std::{fmt, mem::size_of, str};
|
||||
use std::{fmt, mem::size_of, str, sync::Arc};
|
||||
|
||||
pub struct ComputePass {
|
||||
/// All pass data & records is stored here.
|
||||
@ -282,7 +281,9 @@ impl Global {
|
||||
/// If creation fails, an invalid pass is returned.
|
||||
/// Any operation on an invalid pass will return an error.
|
||||
///
|
||||
/// If successful, puts the encoder into the [`CommandEncoderStatus::Locked`] state.
|
||||
/// If successful, puts the encoder into the [`Locked`] state.
|
||||
///
|
||||
/// [`Locked`]: crate::command::CommandEncoderStatus::Locked
|
||||
pub fn command_encoder_create_compute_pass(
|
||||
&self,
|
||||
encoder_id: id::CommandEncoderId,
|
||||
@ -299,11 +300,7 @@ impl Global {
|
||||
|
||||
let cmd_buf = hub.command_buffers.get(encoder_id.into_command_buffer_id());
|
||||
|
||||
match cmd_buf
|
||||
.try_get()
|
||||
.map_err(|e| e.into())
|
||||
.and_then(|mut cmd_buf_data| cmd_buf_data.lock_encoder())
|
||||
{
|
||||
match cmd_buf.data.lock().lock_encoder() {
|
||||
Ok(_) => {}
|
||||
Err(e) => return make_err(e, arc_desc),
|
||||
};
|
||||
@ -355,7 +352,8 @@ impl Global {
|
||||
.hub
|
||||
.command_buffers
|
||||
.get(encoder_id.into_command_buffer_id());
|
||||
let mut cmd_buf_data = cmd_buf.try_get().map_pass_err(pass_scope)?;
|
||||
let mut cmd_buf_data = cmd_buf.data.lock();
|
||||
let cmd_buf_data = cmd_buf_data.get_inner().map_pass_err(pass_scope)?;
|
||||
|
||||
if let Some(ref mut list) = cmd_buf_data.commands {
|
||||
list.push(crate::device::trace::Command::RunComputePass {
|
||||
@ -423,19 +421,16 @@ impl Global {
|
||||
let device = &cmd_buf.device;
|
||||
device.check_is_valid().map_pass_err(pass_scope)?;
|
||||
|
||||
let mut cmd_buf_data = cmd_buf.try_get().map_pass_err(pass_scope)?;
|
||||
cmd_buf_data.unlock_encoder().map_pass_err(pass_scope)?;
|
||||
let cmd_buf_data = &mut *cmd_buf_data;
|
||||
let mut cmd_buf_data = cmd_buf.data.lock();
|
||||
let mut cmd_buf_data_guard = cmd_buf_data.unlock_encoder().map_pass_err(pass_scope)?;
|
||||
let cmd_buf_data = &mut *cmd_buf_data_guard;
|
||||
|
||||
let encoder = &mut cmd_buf_data.encoder;
|
||||
let status = &mut cmd_buf_data.status;
|
||||
|
||||
// We automatically keep extending command buffers over time, and because
|
||||
// we want to insert a command buffer _before_ what we're about to record,
|
||||
// we need to make sure to close the previous one.
|
||||
encoder.close(&cmd_buf.device).map_pass_err(pass_scope)?;
|
||||
// will be reset to true if recording is done without errors
|
||||
*status = CommandEncoderStatus::Error;
|
||||
let raw_encoder = encoder.open(&cmd_buf.device).map_pass_err(pass_scope)?;
|
||||
|
||||
let mut state = State {
|
||||
@ -605,10 +600,6 @@ impl Global {
|
||||
state.raw_encoder.end_compute_pass();
|
||||
}
|
||||
|
||||
// We've successfully recorded the compute pass, bring the
|
||||
// command buffer out of the error state.
|
||||
*status = CommandEncoderStatus::Recording;
|
||||
|
||||
let State {
|
||||
snatch_guard,
|
||||
tracker,
|
||||
@ -641,6 +632,7 @@ impl Global {
|
||||
encoder
|
||||
.close_and_swap(&cmd_buf.device)
|
||||
.map_pass_err(pass_scope)?;
|
||||
cmd_buf_data_guard.mark_successful();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -13,6 +13,7 @@ mod render_command;
|
||||
mod timestamp_writes;
|
||||
mod transfer;
|
||||
|
||||
use std::mem::{self, ManuallyDrop};
|
||||
use std::sync::Arc;
|
||||
|
||||
pub(crate) use self::clear::clear_texture;
|
||||
@ -46,7 +47,6 @@ use crate::device::trace::Command as TraceCommand;
|
||||
const PUSH_CONSTANT_CLEAR_ARRAY: &[u32] = &[0_u32; 64];
|
||||
|
||||
/// The current state of a [`CommandBuffer`].
|
||||
#[derive(Debug)]
|
||||
pub(crate) enum CommandEncoderStatus {
|
||||
/// Ready to record commands. An encoder's initial state.
|
||||
///
|
||||
@ -59,7 +59,7 @@ pub(crate) enum CommandEncoderStatus {
|
||||
///
|
||||
/// [`command_encoder_clear_buffer`]: Global::command_encoder_clear_buffer
|
||||
/// [`compute_pass_end`]: Global::compute_pass_end
|
||||
Recording,
|
||||
Recording(CommandBufferMutable),
|
||||
|
||||
/// Locked by a render or compute pass.
|
||||
///
|
||||
@ -67,9 +67,9 @@ pub(crate) enum CommandEncoderStatus {
|
||||
/// and exited when the pass is ended.
|
||||
///
|
||||
/// As long as the command encoder is locked, any command building operation on it will fail
|
||||
/// and put the encoder into the [`CommandEncoderStatus::Error`] state.
|
||||
/// and put the encoder into the [`Self::Error`] state.
|
||||
/// See <https://www.w3.org/TR/webgpu/#encoder-state-locked>
|
||||
Locked,
|
||||
Locked(CommandBufferMutable),
|
||||
|
||||
/// Command recording is complete, and the buffer is ready for submission.
|
||||
///
|
||||
@ -78,21 +78,147 @@ pub(crate) enum CommandEncoderStatus {
|
||||
///
|
||||
/// [`Global::queue_submit`] drops command buffers unless they are
|
||||
/// in this state.
|
||||
Finished,
|
||||
Finished(CommandBufferMutable),
|
||||
|
||||
/// An error occurred while recording a compute or render pass.
|
||||
///
|
||||
/// When a `CommandEncoder` is left in this state, we have also
|
||||
/// returned an error result from the function that encountered
|
||||
/// the problem. Future attempts to use the encoder (for example,
|
||||
/// calls to [`CommandBufferMutable::check_recording`]) will also return
|
||||
/// errors.
|
||||
///
|
||||
/// Calling [`Global::command_encoder_finish`] in this state
|
||||
/// discards the command buffer under construction.
|
||||
/// calls to [`Self::record`]) will also return errors.
|
||||
Error,
|
||||
}
|
||||
|
||||
impl CommandEncoderStatus {
|
||||
/// Checks that the encoder is in the [`Self::Recording`] state.
|
||||
pub(crate) fn record(&mut self) -> Result<&mut CommandBufferMutable, CommandEncoderError> {
|
||||
match self {
|
||||
Self::Recording(inner) => Ok(inner),
|
||||
Self::Locked(_) => {
|
||||
*self = Self::Error;
|
||||
Err(CommandEncoderError::Locked)
|
||||
}
|
||||
Self::Finished(_) => Err(CommandEncoderError::NotRecording),
|
||||
Self::Error => Err(CommandEncoderError::Invalid),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "trace")]
|
||||
fn get_inner(&mut self) -> Result<&mut CommandBufferMutable, CommandEncoderError> {
|
||||
match self {
|
||||
Self::Locked(inner) | Self::Finished(inner) | Self::Recording(inner) => Ok(inner),
|
||||
Self::Error => Err(CommandEncoderError::Invalid),
|
||||
}
|
||||
}
|
||||
|
||||
/// Locks the encoder by putting it in the [`Self::Locked`] state.
|
||||
///
|
||||
/// Call [`Self::unlock_encoder`] to put the [`CommandBuffer`] back into the [`Self::Recording`] state.
|
||||
fn lock_encoder(&mut self) -> Result<(), CommandEncoderError> {
|
||||
match mem::replace(self, Self::Error) {
|
||||
Self::Recording(inner) => {
|
||||
*self = Self::Locked(inner);
|
||||
Ok(())
|
||||
}
|
||||
Self::Finished(inner) => {
|
||||
*self = Self::Finished(inner);
|
||||
Err(CommandEncoderError::NotRecording)
|
||||
}
|
||||
Self::Locked(_) => Err(CommandEncoderError::Locked),
|
||||
Self::Error => Err(CommandEncoderError::Invalid),
|
||||
}
|
||||
}
|
||||
|
||||
/// Unlocks the [`CommandBuffer`] and puts it back into the [`Self::Recording`] state.
|
||||
///
|
||||
/// This function is the unlocking counterpart to [`Self::lock_encoder`].
|
||||
///
|
||||
/// It is only valid to call this function if the encoder is in the [`Self::Locked`] state.
|
||||
fn unlock_encoder(&mut self) -> Result<RecordingGuard<'_>, CommandEncoderError> {
|
||||
match mem::replace(self, Self::Error) {
|
||||
Self::Locked(inner) => {
|
||||
*self = Self::Recording(inner);
|
||||
Ok(RecordingGuard { inner: self })
|
||||
}
|
||||
Self::Finished(inner) => {
|
||||
*self = Self::Finished(inner);
|
||||
Err(CommandEncoderError::NotRecording)
|
||||
}
|
||||
Self::Recording(_) => Err(CommandEncoderError::Invalid),
|
||||
Self::Error => Err(CommandEncoderError::Invalid),
|
||||
}
|
||||
}
|
||||
|
||||
fn finish(&mut self, device: &Device) -> Result<(), CommandEncoderError> {
|
||||
match mem::replace(self, Self::Error) {
|
||||
Self::Recording(mut inner) => {
|
||||
if let Err(e) = inner.encoder.close(device) {
|
||||
Err(e.into())
|
||||
} else {
|
||||
*self = Self::Finished(inner);
|
||||
// Note: if we want to stop tracking the swapchain texture view,
|
||||
// this is the place to do it.
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
Self::Finished(inner) => {
|
||||
*self = Self::Finished(inner);
|
||||
Err(CommandEncoderError::NotRecording)
|
||||
}
|
||||
Self::Locked(_) => Err(CommandEncoderError::Locked),
|
||||
Self::Error => Err(CommandEncoderError::Invalid),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A guard to enforce error reporting, for a [`CommandBuffer`] in the [`Recording`] state.
|
||||
///
|
||||
/// An [`RecordingGuard`] holds a mutable reference to a [`CommandEncoderStatus`] that
|
||||
/// has been verified to be in the [`Recording`] state. The [`RecordingGuard`] dereferences
|
||||
/// mutably to the [`CommandBufferMutable`] that the status holds.
|
||||
///
|
||||
/// Dropping an [`RecordingGuard`] sets the [`CommandBuffer`]'s state to
|
||||
/// [`CommandEncoderStatus::Error`]. If your use of the guard was
|
||||
/// successful, call its [`mark_successful`] method to dispose of it.
|
||||
///
|
||||
/// [`Recording`]: CommandEncoderStatus::Recording
|
||||
/// [`mark_successful`]: Self::mark_successful
|
||||
pub(crate) struct RecordingGuard<'a> {
|
||||
inner: &'a mut CommandEncoderStatus,
|
||||
}
|
||||
|
||||
impl<'a> RecordingGuard<'a> {
|
||||
pub(crate) fn mark_successful(self) {
|
||||
mem::forget(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Drop for RecordingGuard<'a> {
|
||||
fn drop(&mut self) {
|
||||
*self.inner = CommandEncoderStatus::Error;
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> std::ops::Deref for RecordingGuard<'a> {
|
||||
type Target = CommandBufferMutable;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
match &*self.inner {
|
||||
CommandEncoderStatus::Recording(command_buffer_mutable) => command_buffer_mutable,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> std::ops::DerefMut for RecordingGuard<'a> {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
match self.inner {
|
||||
CommandEncoderStatus::Recording(command_buffer_mutable) => command_buffer_mutable,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 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
|
||||
@ -121,7 +247,7 @@ pub(crate) struct CommandEncoder {
|
||||
///
|
||||
/// [`CommandEncoder`]: hal::Api::CommandEncoder
|
||||
/// [`CommandAllocator`]: crate::command::CommandAllocator
|
||||
pub(crate) raw: Box<dyn hal::DynCommandEncoder>,
|
||||
pub(crate) raw: ManuallyDrop<Box<dyn hal::DynCommandEncoder>>,
|
||||
|
||||
/// All the raw command buffers for our owning [`CommandBuffer`], in
|
||||
/// submission order.
|
||||
@ -136,6 +262,8 @@ pub(crate) struct CommandEncoder {
|
||||
/// [`wgpu_hal::CommandEncoder`]: hal::CommandEncoder
|
||||
pub(crate) list: Vec<Box<dyn hal::DynCommandBuffer>>,
|
||||
|
||||
pub(crate) device: Arc<Device>,
|
||||
|
||||
/// True if `raw` is in the "recording" state.
|
||||
///
|
||||
/// See the documentation for [`wgpu_hal::CommandEncoder`] for
|
||||
@ -205,16 +333,6 @@ impl CommandEncoder {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Discard the command buffer under construction, if any.
|
||||
///
|
||||
/// The underlying hal encoder is closed, if it was recording.
|
||||
pub(crate) fn discard(&mut self) {
|
||||
if self.is_open {
|
||||
self.is_open = false;
|
||||
unsafe { self.raw.discard_encoding() };
|
||||
}
|
||||
}
|
||||
|
||||
/// Begin recording a new command buffer, if we haven't already.
|
||||
///
|
||||
/// The underlying hal encoder is put in the "recording" state.
|
||||
@ -244,6 +362,20 @@ impl CommandEncoder {
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for CommandEncoder {
|
||||
fn drop(&mut self) {
|
||||
if self.is_open {
|
||||
unsafe { self.raw.discard_encoding() };
|
||||
}
|
||||
unsafe {
|
||||
self.raw.reset_all(mem::take(&mut self.list));
|
||||
}
|
||||
// SAFETY: We are in the Drop impl and we don't use self.raw anymore after this point.
|
||||
let raw = unsafe { ManuallyDrop::take(&mut self.raw) };
|
||||
self.device.command_allocator.release_encoder(raw);
|
||||
}
|
||||
}
|
||||
|
||||
/// 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 {
|
||||
@ -261,9 +393,6 @@ pub struct CommandBufferMutable {
|
||||
/// [`wgpu_hal::Api::CommandBuffer`]: hal::Api::CommandBuffer
|
||||
pub(crate) encoder: CommandEncoder,
|
||||
|
||||
/// The current state of this command buffer's encoder.
|
||||
status: CommandEncoderStatus,
|
||||
|
||||
/// All the resources that the commands recorded so far have referred to.
|
||||
pub(crate) trackers: Tracker,
|
||||
|
||||
@ -296,86 +425,6 @@ impl CommandBufferMutable {
|
||||
Ok((encoder, tracker))
|
||||
}
|
||||
|
||||
fn lock_encoder_impl(&mut self, lock: bool) -> Result<(), CommandEncoderError> {
|
||||
match self.status {
|
||||
CommandEncoderStatus::Recording => {
|
||||
if lock {
|
||||
self.status = CommandEncoderStatus::Locked;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
CommandEncoderStatus::Locked => {
|
||||
// Any operation on a locked encoder is required to put it into the invalid/error state.
|
||||
// See https://www.w3.org/TR/webgpu/#encoder-state-locked
|
||||
self.encoder.discard();
|
||||
self.status = CommandEncoderStatus::Error;
|
||||
Err(CommandEncoderError::Locked)
|
||||
}
|
||||
CommandEncoderStatus::Finished => Err(CommandEncoderError::NotRecording),
|
||||
CommandEncoderStatus::Error => Err(CommandEncoderError::Invalid),
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks that the encoder is in the [`CommandEncoderStatus::Recording`] state.
|
||||
fn check_recording(&mut self) -> Result<(), CommandEncoderError> {
|
||||
self.lock_encoder_impl(false)
|
||||
}
|
||||
|
||||
/// Locks the encoder by putting it in the [`CommandEncoderStatus::Locked`] state.
|
||||
///
|
||||
/// Call [`CommandBufferMutable::unlock_encoder`] to put the [`CommandBuffer`] back into the [`CommandEncoderStatus::Recording`] state.
|
||||
fn lock_encoder(&mut self) -> Result<(), CommandEncoderError> {
|
||||
self.lock_encoder_impl(true)
|
||||
}
|
||||
|
||||
/// Unlocks the [`CommandBuffer`] and puts it back into the [`CommandEncoderStatus::Recording`] state.
|
||||
///
|
||||
/// This function is the counterpart to [`CommandBufferMutable::lock_encoder`].
|
||||
/// It is only valid to call this function if the encoder is in the [`CommandEncoderStatus::Locked`] state.
|
||||
fn unlock_encoder(&mut self) -> Result<(), CommandEncoderError> {
|
||||
match self.status {
|
||||
CommandEncoderStatus::Recording => Err(CommandEncoderError::Invalid),
|
||||
CommandEncoderStatus::Locked => {
|
||||
self.status = CommandEncoderStatus::Recording;
|
||||
Ok(())
|
||||
}
|
||||
CommandEncoderStatus::Finished => Err(CommandEncoderError::Invalid),
|
||||
CommandEncoderStatus::Error => Err(CommandEncoderError::Invalid),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn check_finished(&self) -> Result<(), CommandEncoderError> {
|
||||
match self.status {
|
||||
CommandEncoderStatus::Finished => Ok(()),
|
||||
_ => Err(CommandEncoderError::Invalid),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn finish(&mut self, device: &Device) -> Result<(), CommandEncoderError> {
|
||||
match self.status {
|
||||
CommandEncoderStatus::Recording => {
|
||||
if let Err(e) = self.encoder.close(device) {
|
||||
Err(e.into())
|
||||
} else {
|
||||
self.status = CommandEncoderStatus::Finished;
|
||||
// Note: if we want to stop tracking the swapchain texture view,
|
||||
// this is the place to do it.
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
CommandEncoderStatus::Locked => {
|
||||
self.encoder.discard();
|
||||
self.status = CommandEncoderStatus::Error;
|
||||
Err(CommandEncoderError::Locked)
|
||||
}
|
||||
CommandEncoderStatus::Finished => Err(CommandEncoderError::NotRecording),
|
||||
CommandEncoderStatus::Error => {
|
||||
self.encoder.discard();
|
||||
Err(CommandEncoderError::Invalid)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn into_baked_commands(self) -> BakedCommands {
|
||||
BakedCommands {
|
||||
encoder: self.encoder,
|
||||
@ -384,13 +433,6 @@ impl CommandBufferMutable {
|
||||
texture_memory_actions: self.texture_memory_actions,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn destroy(mut self) {
|
||||
self.encoder.discard();
|
||||
unsafe {
|
||||
self.encoder.raw.reset_all(self.encoder.list);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A buffer of commands to be submitted to the GPU for execution.
|
||||
@ -423,15 +465,12 @@ pub struct CommandBuffer {
|
||||
/// When this is submitted, dropped, or destroyed, its contents are
|
||||
/// extracted into a [`BakedCommands`] by
|
||||
/// [`CommandBufferMutable::into_baked_commands`].
|
||||
pub(crate) data: Mutex<Option<CommandBufferMutable>>,
|
||||
pub(crate) data: Mutex<CommandEncoderStatus>,
|
||||
}
|
||||
|
||||
impl Drop for CommandBuffer {
|
||||
fn drop(&mut self) {
|
||||
resource_log!("Drop {}", self.error_ident());
|
||||
if let Some(data) = self.data.lock().take() {
|
||||
data.destroy();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -447,14 +486,14 @@ impl CommandBuffer {
|
||||
label: label.to_string(),
|
||||
data: Mutex::new(
|
||||
rank::COMMAND_BUFFER_DATA,
|
||||
Some(CommandBufferMutable {
|
||||
CommandEncoderStatus::Recording(CommandBufferMutable {
|
||||
encoder: CommandEncoder {
|
||||
raw: encoder,
|
||||
is_open: false,
|
||||
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),
|
||||
},
|
||||
status: CommandEncoderStatus::Recording,
|
||||
trackers: Tracker::new(),
|
||||
buffer_memory_init_actions: Default::default(),
|
||||
texture_memory_actions: Default::default(),
|
||||
@ -477,7 +516,7 @@ impl CommandBuffer {
|
||||
device: device.clone(),
|
||||
support_clear_texture: device.features.contains(wgt::Features::CLEAR_TEXTURE),
|
||||
label: label.to_string(),
|
||||
data: Mutex::new(rank::COMMAND_BUFFER_DATA, None),
|
||||
data: Mutex::new(rank::COMMAND_BUFFER_DATA, CommandEncoderStatus::Error),
|
||||
}
|
||||
}
|
||||
|
||||
@ -559,19 +598,14 @@ impl CommandBuffer {
|
||||
}
|
||||
|
||||
impl CommandBuffer {
|
||||
pub fn try_get<'a>(
|
||||
&'a self,
|
||||
) -> Result<parking_lot::MappedMutexGuard<'a, CommandBufferMutable>, InvalidResourceError> {
|
||||
let g = self.data.lock();
|
||||
crate::lock::MutexGuard::try_map(g, |data| data.as_mut())
|
||||
.map_err(|_| InvalidResourceError(self.error_ident()))
|
||||
}
|
||||
|
||||
pub fn try_take<'a>(&'a self) -> Result<CommandBufferMutable, InvalidResourceError> {
|
||||
self.data
|
||||
.lock()
|
||||
.take()
|
||||
.ok_or_else(|| InvalidResourceError(self.error_ident()))
|
||||
pub fn take_finished<'a>(&'a self) -> Result<CommandBufferMutable, InvalidResourceError> {
|
||||
let status = mem::replace(&mut *self.data.lock(), CommandEncoderStatus::Error);
|
||||
match status {
|
||||
CommandEncoderStatus::Finished(command_buffer_mutable) => Ok(command_buffer_mutable),
|
||||
CommandEncoderStatus::Recording(_)
|
||||
| CommandEncoderStatus::Locked(_)
|
||||
| CommandEncoderStatus::Error => Err(InvalidResourceError(self.error_ident())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -663,11 +697,7 @@ impl Global {
|
||||
|
||||
let cmd_buf = hub.command_buffers.get(encoder_id.into_command_buffer_id());
|
||||
|
||||
let error = match cmd_buf
|
||||
.try_get()
|
||||
.map_err(|e| e.into())
|
||||
.and_then(|mut cmd_buf_data| cmd_buf_data.finish(&cmd_buf.device))
|
||||
{
|
||||
let error = match cmd_buf.data.lock().finish(&cmd_buf.device) {
|
||||
Ok(_) => None,
|
||||
Err(e) => Some(e),
|
||||
};
|
||||
@ -686,8 +716,8 @@ impl Global {
|
||||
let hub = &self.hub;
|
||||
|
||||
let cmd_buf = hub.command_buffers.get(encoder_id.into_command_buffer_id());
|
||||
let mut cmd_buf_data = cmd_buf.try_get()?;
|
||||
cmd_buf_data.check_recording()?;
|
||||
let mut cmd_buf_data = cmd_buf.data.lock();
|
||||
let cmd_buf_data = cmd_buf_data.record()?;
|
||||
|
||||
#[cfg(feature = "trace")]
|
||||
if let Some(ref mut list) = cmd_buf_data.commands {
|
||||
@ -718,8 +748,8 @@ impl Global {
|
||||
let hub = &self.hub;
|
||||
|
||||
let cmd_buf = hub.command_buffers.get(encoder_id.into_command_buffer_id());
|
||||
let mut cmd_buf_data = cmd_buf.try_get()?;
|
||||
cmd_buf_data.check_recording()?;
|
||||
let mut cmd_buf_data = cmd_buf.data.lock();
|
||||
let cmd_buf_data = cmd_buf_data.record()?;
|
||||
|
||||
#[cfg(feature = "trace")]
|
||||
if let Some(ref mut list) = cmd_buf_data.commands {
|
||||
@ -749,8 +779,8 @@ impl Global {
|
||||
let hub = &self.hub;
|
||||
|
||||
let cmd_buf = hub.command_buffers.get(encoder_id.into_command_buffer_id());
|
||||
let mut cmd_buf_data = cmd_buf.try_get()?;
|
||||
cmd_buf_data.check_recording()?;
|
||||
let mut cmd_buf_data = cmd_buf.data.lock();
|
||||
let cmd_buf_data = cmd_buf_data.record()?;
|
||||
|
||||
#[cfg(feature = "trace")]
|
||||
if let Some(ref mut list) = cmd_buf_data.commands {
|
||||
|
@ -321,8 +321,8 @@ impl Global {
|
||||
let cmd_buf = hub
|
||||
.command_buffers
|
||||
.get(command_encoder_id.into_command_buffer_id());
|
||||
let mut cmd_buf_data = cmd_buf.try_get()?;
|
||||
cmd_buf_data.check_recording()?;
|
||||
let mut cmd_buf_data = cmd_buf.data.lock();
|
||||
let cmd_buf_data = cmd_buf_data.record()?;
|
||||
|
||||
cmd_buf
|
||||
.device
|
||||
@ -361,8 +361,8 @@ impl Global {
|
||||
let cmd_buf = hub
|
||||
.command_buffers
|
||||
.get(command_encoder_id.into_command_buffer_id());
|
||||
let mut cmd_buf_data = cmd_buf.try_get()?;
|
||||
cmd_buf_data.check_recording()?;
|
||||
let mut cmd_buf_data = cmd_buf.data.lock();
|
||||
let cmd_buf_data = cmd_buf_data.record()?;
|
||||
|
||||
#[cfg(feature = "trace")]
|
||||
if let Some(ref mut list) = cmd_buf_data.commands {
|
||||
|
@ -129,7 +129,7 @@ impl Global {
|
||||
#[cfg(feature = "trace")]
|
||||
let trace_tlas: Vec<TlasBuildEntry> = tlas_iter.collect();
|
||||
#[cfg(feature = "trace")]
|
||||
if let Some(ref mut list) = cmd_buf.data.lock().as_mut().unwrap().commands {
|
||||
if let Some(ref mut list) = cmd_buf.data.lock().get_inner()?.commands {
|
||||
list.push(
|
||||
crate::device::trace::Command::BuildAccelerationStructuresUnsafeTlas {
|
||||
blas: trace_blas.clone(),
|
||||
@ -173,7 +173,7 @@ impl Global {
|
||||
let mut scratch_buffer_blas_size = 0;
|
||||
let mut blas_storage = Vec::new();
|
||||
let mut cmd_buf_data = cmd_buf.data.lock();
|
||||
let cmd_buf_data = cmd_buf_data.as_mut().unwrap();
|
||||
let cmd_buf_data = cmd_buf_data.record()?;
|
||||
|
||||
iter_blas(
|
||||
blas_iter,
|
||||
@ -437,7 +437,7 @@ impl Global {
|
||||
.collect();
|
||||
|
||||
#[cfg(feature = "trace")]
|
||||
if let Some(ref mut list) = cmd_buf.data.lock().as_mut().unwrap().commands {
|
||||
if let Some(ref mut list) = cmd_buf.data.lock().get_inner()?.commands {
|
||||
list.push(crate::device::trace::Command::BuildAccelerationStructures {
|
||||
blas: trace_blas.clone(),
|
||||
tlas: trace_tlas.clone(),
|
||||
@ -488,7 +488,7 @@ impl Global {
|
||||
let mut scratch_buffer_blas_size = 0;
|
||||
let mut blas_storage = Vec::new();
|
||||
let mut cmd_buf_data = cmd_buf.data.lock();
|
||||
let cmd_buf_data = cmd_buf_data.as_mut().unwrap();
|
||||
let cmd_buf_data = cmd_buf_data.record()?;
|
||||
|
||||
iter_blas(
|
||||
blas_iter,
|
||||
|
@ -14,8 +14,8 @@ use crate::{
|
||||
end_occlusion_query, end_pipeline_statistics_query,
|
||||
memory_init::{fixup_discarded_surfaces, SurfacesInDiscardState},
|
||||
ArcPassTimestampWrites, BasePass, BindGroupStateChange, CommandBuffer, CommandEncoderError,
|
||||
CommandEncoderStatus, DrawError, ExecutionError, MapPassErr, PassErrorScope,
|
||||
PassTimestampWrites, QueryUseError, RenderCommandError, StateChange,
|
||||
DrawError, ExecutionError, MapPassErr, PassErrorScope, PassTimestampWrites, QueryUseError,
|
||||
RenderCommandError, StateChange,
|
||||
},
|
||||
device::{
|
||||
AttachmentData, Device, DeviceError, MissingDownlevelFlags, MissingFeatures,
|
||||
@ -45,8 +45,7 @@ use serde::Deserialize;
|
||||
#[cfg(feature = "serde")]
|
||||
use serde::Serialize;
|
||||
|
||||
use std::sync::Arc;
|
||||
use std::{borrow::Cow, fmt, iter, mem::size_of, num::NonZeroU32, ops::Range, str};
|
||||
use std::{borrow::Cow, fmt, iter, mem::size_of, num::NonZeroU32, ops::Range, str, sync::Arc};
|
||||
|
||||
use super::render_command::ArcRenderCommand;
|
||||
use super::{
|
||||
@ -1321,7 +1320,9 @@ impl Global {
|
||||
/// If creation fails, an invalid pass is returned.
|
||||
/// Any operation on an invalid pass will return an error.
|
||||
///
|
||||
/// If successful, puts the encoder into the [`CommandEncoderStatus::Locked`] state.
|
||||
/// If successful, puts the encoder into the [`Locked`] state.
|
||||
///
|
||||
/// [`Locked`]: crate::command::CommandEncoderStatus::Locked
|
||||
pub fn command_encoder_create_render_pass(
|
||||
&self,
|
||||
encoder_id: id::CommandEncoderId,
|
||||
@ -1432,11 +1433,7 @@ impl Global {
|
||||
|
||||
let cmd_buf = hub.command_buffers.get(encoder_id.into_command_buffer_id());
|
||||
|
||||
match cmd_buf
|
||||
.try_get()
|
||||
.map_err(|e| e.into())
|
||||
.and_then(|mut cmd_buf_data| cmd_buf_data.lock_encoder())
|
||||
{
|
||||
match cmd_buf.data.lock().lock_encoder() {
|
||||
Ok(_) => {}
|
||||
Err(e) => return make_err(e, arc_desc),
|
||||
};
|
||||
@ -1467,7 +1464,8 @@ impl Global {
|
||||
.hub
|
||||
.command_buffers
|
||||
.get(encoder_id.into_command_buffer_id());
|
||||
let mut cmd_buf_data = cmd_buf.try_get().map_pass_err(pass_scope)?;
|
||||
let mut cmd_buf_data = cmd_buf.data.lock();
|
||||
let cmd_buf_data = cmd_buf_data.get_inner().map_pass_err(pass_scope)?;
|
||||
|
||||
if let Some(ref mut list) = cmd_buf_data.commands {
|
||||
list.push(crate::device::trace::Command::RunRenderPass {
|
||||
@ -1542,9 +1540,9 @@ impl Global {
|
||||
base.label.as_deref().unwrap_or("")
|
||||
);
|
||||
|
||||
let mut cmd_buf_data = cmd_buf.try_get().map_pass_err(pass_scope)?;
|
||||
cmd_buf_data.unlock_encoder().map_pass_err(pass_scope)?;
|
||||
let cmd_buf_data = &mut *cmd_buf_data;
|
||||
let mut cmd_buf_data = cmd_buf.data.lock();
|
||||
let mut cmd_buf_data_guard = cmd_buf_data.unlock_encoder().map_pass_err(pass_scope)?;
|
||||
let cmd_buf_data = &mut *cmd_buf_data_guard;
|
||||
|
||||
let device = &cmd_buf.device;
|
||||
let snatch_guard = &device.snatchable_lock.read();
|
||||
@ -1555,7 +1553,6 @@ impl Global {
|
||||
device.check_is_valid().map_pass_err(pass_scope)?;
|
||||
|
||||
let encoder = &mut cmd_buf_data.encoder;
|
||||
let status = &mut cmd_buf_data.status;
|
||||
let tracker = &mut cmd_buf_data.trackers;
|
||||
let buffer_memory_init_actions = &mut cmd_buf_data.buffer_memory_init_actions;
|
||||
let texture_memory_actions = &mut cmd_buf_data.texture_memory_actions;
|
||||
@ -1565,8 +1562,6 @@ impl Global {
|
||||
// we want to insert a command buffer _before_ what we're about to record,
|
||||
// we need to make sure to close the previous one.
|
||||
encoder.close(&cmd_buf.device).map_pass_err(pass_scope)?;
|
||||
// We will reset this to `Recording` if we succeed, acts as a fail-safe.
|
||||
*status = CommandEncoderStatus::Error;
|
||||
encoder
|
||||
.open_pass(hal_label, &cmd_buf.device)
|
||||
.map_pass_err(pass_scope)?;
|
||||
@ -1877,7 +1872,6 @@ impl Global {
|
||||
};
|
||||
|
||||
let encoder = &mut cmd_buf_data.encoder;
|
||||
let status = &mut cmd_buf_data.status;
|
||||
let tracker = &mut cmd_buf_data.trackers;
|
||||
|
||||
{
|
||||
@ -1896,10 +1890,10 @@ impl Global {
|
||||
CommandBuffer::insert_barriers_from_scope(transit, tracker, &scope, snatch_guard);
|
||||
}
|
||||
|
||||
*status = CommandEncoderStatus::Recording;
|
||||
encoder
|
||||
.close_and_swap(&cmd_buf.device)
|
||||
.map_pass_err(pass_scope)?;
|
||||
cmd_buf_data_guard.mark_successful();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -531,8 +531,8 @@ impl Global {
|
||||
let cmd_buf = hub
|
||||
.command_buffers
|
||||
.get(command_encoder_id.into_command_buffer_id());
|
||||
let mut cmd_buf_data = cmd_buf.try_get()?;
|
||||
cmd_buf_data.check_recording()?;
|
||||
let mut cmd_buf_data = cmd_buf.data.lock();
|
||||
let cmd_buf_data = cmd_buf_data.record()?;
|
||||
|
||||
let device = &cmd_buf.device;
|
||||
device.check_is_valid()?;
|
||||
@ -689,8 +689,8 @@ impl Global {
|
||||
let cmd_buf = hub
|
||||
.command_buffers
|
||||
.get(command_encoder_id.into_command_buffer_id());
|
||||
let mut cmd_buf_data = cmd_buf.try_get()?;
|
||||
cmd_buf_data.check_recording()?;
|
||||
let mut cmd_buf_data = cmd_buf.data.lock();
|
||||
let cmd_buf_data = cmd_buf_data.record()?;
|
||||
|
||||
let device = &cmd_buf.device;
|
||||
device.check_is_valid()?;
|
||||
@ -728,7 +728,7 @@ impl Global {
|
||||
// have an easier time inserting "immediate-inits" that may be required
|
||||
// by prior discards in rare cases.
|
||||
handle_dst_texture_init(
|
||||
&mut cmd_buf_data,
|
||||
cmd_buf_data,
|
||||
device,
|
||||
destination,
|
||||
copy_size,
|
||||
@ -842,14 +842,14 @@ impl Global {
|
||||
let cmd_buf = hub
|
||||
.command_buffers
|
||||
.get(command_encoder_id.into_command_buffer_id());
|
||||
let mut cmd_buf_data = cmd_buf.try_get()?;
|
||||
cmd_buf_data.check_recording()?;
|
||||
let mut cmd_buf_data = cmd_buf.data.lock();
|
||||
let cmd_buf_data = cmd_buf_data.record()?;
|
||||
|
||||
let device = &cmd_buf.device;
|
||||
device.check_is_valid()?;
|
||||
|
||||
#[cfg(feature = "trace")]
|
||||
if let Some(ref mut list) = cmd_buf_data.commands {
|
||||
if let Some(list) = cmd_buf_data.commands.as_mut() {
|
||||
list.push(TraceCommand::CopyTextureToBuffer {
|
||||
src: *source,
|
||||
dst: *destination,
|
||||
@ -877,7 +877,7 @@ impl Global {
|
||||
// have an easier time inserting "immediate-inits" that may be required
|
||||
// by prior discards in rare cases.
|
||||
handle_src_texture_init(
|
||||
&mut cmd_buf_data,
|
||||
cmd_buf_data,
|
||||
device,
|
||||
source,
|
||||
copy_size,
|
||||
@ -1009,8 +1009,8 @@ impl Global {
|
||||
let cmd_buf = hub
|
||||
.command_buffers
|
||||
.get(command_encoder_id.into_command_buffer_id());
|
||||
let mut cmd_buf_data = cmd_buf.try_get()?;
|
||||
cmd_buf_data.check_recording()?;
|
||||
let mut cmd_buf_data = cmd_buf.data.lock();
|
||||
let cmd_buf_data = cmd_buf_data.record()?;
|
||||
|
||||
let device = &cmd_buf.device;
|
||||
device.check_is_valid()?;
|
||||
@ -1074,7 +1074,7 @@ impl Global {
|
||||
// have an easier time inserting "immediate-inits" that may be required
|
||||
// by prior discards in rare cases.
|
||||
handle_src_texture_init(
|
||||
&mut cmd_buf_data,
|
||||
cmd_buf_data,
|
||||
device,
|
||||
source,
|
||||
copy_size,
|
||||
@ -1082,7 +1082,7 @@ impl Global {
|
||||
&snatch_guard,
|
||||
)?;
|
||||
handle_dst_texture_init(
|
||||
&mut cmd_buf_data,
|
||||
cmd_buf_data,
|
||||
device,
|
||||
destination,
|
||||
copy_size,
|
||||
|
@ -320,7 +320,6 @@ impl LifetimeTracker {
|
||||
pub fn triage_submissions(
|
||||
&mut self,
|
||||
last_done: SubmissionIndex,
|
||||
command_allocator: &crate::command::CommandAllocator,
|
||||
) -> SmallVec<[SubmittedWorkDoneClosure; 1]> {
|
||||
profiling::scope!("triage_submissions");
|
||||
|
||||
@ -336,8 +335,10 @@ impl LifetimeTracker {
|
||||
for a in self.active.drain(..done_count) {
|
||||
self.ready_to_map.extend(a.mapped);
|
||||
for encoder in a.encoders {
|
||||
let raw = unsafe { encoder.land() };
|
||||
command_allocator.release_encoder(raw);
|
||||
// This involves actually decrementing the ref count of all command buffer
|
||||
// resources, so can be _very_ expensive.
|
||||
profiling::scope!("drop command buffer trackers");
|
||||
drop(encoder);
|
||||
}
|
||||
drop(a.temp_resources);
|
||||
work_done_closures.extend(a.work_done_closures);
|
||||
|
@ -31,7 +31,8 @@ use smallvec::SmallVec;
|
||||
use crate::resource::{Blas, DestroyedAccelerationStructure, Tlas};
|
||||
use crate::scratch::ScratchBuffer;
|
||||
use std::{
|
||||
iter, mem,
|
||||
iter,
|
||||
mem::{self, ManuallyDrop},
|
||||
ptr::NonNull,
|
||||
sync::{atomic::Ordering, Arc},
|
||||
};
|
||||
@ -113,8 +114,7 @@ impl Queue {
|
||||
bool,
|
||||
) {
|
||||
let mut life_tracker = self.lock_life();
|
||||
let submission_closures =
|
||||
life_tracker.triage_submissions(submission_index, &self.device.command_allocator);
|
||||
let submission_closures = life_tracker.triage_submissions(submission_index);
|
||||
|
||||
let mapping_closures = life_tracker.handle_mapping(snatch_guard);
|
||||
|
||||
@ -325,27 +325,6 @@ pub(crate) struct EncoderInFlight {
|
||||
pub(crate) pending_tlas_s: FastHashMap<TrackerIndex, Arc<Tlas>>,
|
||||
}
|
||||
|
||||
impl EncoderInFlight {
|
||||
/// Free all of our command buffers.
|
||||
///
|
||||
/// Return the command encoder, fully reset and ready to be
|
||||
/// reused.
|
||||
pub(crate) unsafe fn land(mut self) -> Box<dyn hal::DynCommandEncoder> {
|
||||
unsafe { self.inner.raw.reset_all(self.inner.list) };
|
||||
{
|
||||
// This involves actually decrementing the ref count of all command buffer
|
||||
// resources, so can be _very_ expensive.
|
||||
profiling::scope!("drop command buffer trackers");
|
||||
drop(self.trackers);
|
||||
drop(self.pending_buffers);
|
||||
drop(self.pending_textures);
|
||||
drop(self.pending_blas_s);
|
||||
drop(self.pending_tlas_s);
|
||||
}
|
||||
self.inner.raw
|
||||
}
|
||||
}
|
||||
|
||||
/// A private command encoder for writes made directly on the device
|
||||
/// or queue.
|
||||
///
|
||||
@ -444,7 +423,7 @@ impl PendingWrites {
|
||||
fn pre_submit(
|
||||
&mut self,
|
||||
command_allocator: &CommandAllocator,
|
||||
device: &Device,
|
||||
device: &Arc<Device>,
|
||||
queue: &Queue,
|
||||
) -> Result<Option<EncoderInFlight>, DeviceError> {
|
||||
if self.is_recording {
|
||||
@ -463,8 +442,9 @@ impl PendingWrites {
|
||||
|
||||
let encoder = EncoderInFlight {
|
||||
inner: crate::command::CommandEncoder {
|
||||
raw: mem::replace(&mut self.command_encoder, new_encoder),
|
||||
raw: ManuallyDrop::new(mem::replace(&mut self.command_encoder, new_encoder)),
|
||||
list: vec![cmd_buf],
|
||||
device: device.clone(),
|
||||
is_open: false,
|
||||
hal_label: None,
|
||||
},
|
||||
@ -1185,7 +1165,7 @@ impl Queue {
|
||||
// Note that we are required to invalidate all command buffers in both the success and failure paths.
|
||||
// This is why we `continue` and don't early return via `?`.
|
||||
#[allow(unused_mut)]
|
||||
let mut cmd_buf_data = command_buffer.try_take();
|
||||
let mut cmd_buf_data = command_buffer.take_finished();
|
||||
|
||||
#[cfg(feature = "trace")]
|
||||
if let Some(ref mut trace) = *self.device.trace.lock() {
|
||||
@ -1198,9 +1178,6 @@ impl Queue {
|
||||
}
|
||||
|
||||
if first_error.is_some() {
|
||||
if let Ok(cmd_buf_data) = cmd_buf_data {
|
||||
cmd_buf_data.destroy();
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -1216,7 +1193,6 @@ impl Queue {
|
||||
);
|
||||
if let Err(err) = res {
|
||||
first_error.get_or_insert(err);
|
||||
cmd_buf_data.destroy();
|
||||
continue;
|
||||
}
|
||||
cmd_buf_data.into_baked_commands()
|
||||
@ -1608,7 +1584,6 @@ fn validate_command_buffer(
|
||||
used_surface_textures: &mut track::TextureUsageScope,
|
||||
) -> Result<(), QueueSubmitError> {
|
||||
command_buffer.same_device_as(queue)?;
|
||||
cmd_buf_data.check_finished()?;
|
||||
|
||||
{
|
||||
profiling::scope!("check resource state");
|
||||
|
@ -3535,9 +3535,7 @@ impl Device {
|
||||
.map_err(|e| self.handle_hal_error(e))?;
|
||||
drop(fence);
|
||||
if let Some(queue) = self.get_queue() {
|
||||
let closures = queue
|
||||
.lock_life()
|
||||
.triage_submissions(submission_index, &self.command_allocator);
|
||||
let closures = queue.lock_life().triage_submissions(submission_index);
|
||||
assert!(
|
||||
closures.is_empty(),
|
||||
"wait_for_submit is not expected to work with closures"
|
||||
|
@ -78,15 +78,6 @@ impl<T> Mutex<T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> MutexGuard<'a, T> {
|
||||
pub fn try_map<U: ?Sized, F>(s: Self, f: F) -> Result<parking_lot::MappedMutexGuard<'a, U>, ()>
|
||||
where
|
||||
F: FnOnce(&mut T) -> Option<&mut U>,
|
||||
{
|
||||
parking_lot::MutexGuard::try_map(s.inner, f).map_err(|_| ())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> std::ops::Deref for MutexGuard<'a, T> {
|
||||
type Target = T;
|
||||
|
||||
|
@ -30,15 +30,6 @@ impl<T> Mutex<T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> MutexGuard<'a, T> {
|
||||
pub fn try_map<U: ?Sized, F>(s: Self, f: F) -> Result<parking_lot::MappedMutexGuard<'a, U>, ()>
|
||||
where
|
||||
F: FnOnce(&mut T) -> Option<&mut U>,
|
||||
{
|
||||
parking_lot::MutexGuard::try_map(s.0, f).map_err(|_| ())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> std::ops::Deref for MutexGuard<'a, T> {
|
||||
type Target = T;
|
||||
|
||||
|
@ -1480,9 +1480,10 @@ impl Global {
|
||||
let hub = &self.hub;
|
||||
|
||||
let cmd_buf = hub.command_buffers.get(id.into_command_buffer_id());
|
||||
let cmd_buf_data = cmd_buf.try_get();
|
||||
let mut cmd_buf_data = cmd_buf.data.lock();
|
||||
let cmd_buf_data = cmd_buf_data.record();
|
||||
|
||||
if let Ok(mut cmd_buf_data) = cmd_buf_data {
|
||||
if let Ok(cmd_buf_data) = cmd_buf_data {
|
||||
let cmd_buf_raw = cmd_buf_data
|
||||
.encoder
|
||||
.open(&cmd_buf.device)
|
||||
|
Loading…
Reference in New Issue
Block a user