[core] Move CommandAllocator into its own module.

No intended change in behavior.
This commit is contained in:
Jim Blandy 2024-04-15 11:43:19 -07:00 committed by Erich Gubler
parent c6efbef8a6
commit b9781ee6e2
6 changed files with 71 additions and 63 deletions

View File

@ -0,0 +1,62 @@
use crate::hal_api::HalApi;
use crate::resource_log;
use hal::Device as _;
/// A pool of free [`wgpu_hal::CommandEncoder`]s, owned by a `Device`.
///
/// Each encoder in this list is in the "closed" state.
///
/// Since a raw [`CommandEncoder`][ce] is itself a pool for allocating
/// raw [`CommandBuffer`][cb]s, this is a pool of pools.
///
/// [ce]: wgpu_hal::CommandEncoder
/// [cb]: wgpu_hal::Api::CommandBuffer
pub(crate) struct CommandAllocator<A: HalApi> {
free_encoders: Vec<A::CommandEncoder>,
}
impl<A: HalApi> CommandAllocator<A> {
pub(crate) fn new() -> Self {
Self {
free_encoders: Vec::new(),
}
}
/// Return a fresh [`wgpu_hal::CommandEncoder`] in the "closed" state.
///
/// If we have free encoders in the pool, take one of those. Otherwise,
/// create a new one on `device`.
pub(crate) fn acquire_encoder(
&mut self,
device: &A::Device,
queue: &A::Queue,
) -> Result<A::CommandEncoder, hal::DeviceError> {
match self.free_encoders.pop() {
Some(encoder) => Ok(encoder),
None => unsafe {
let hal_desc = hal::CommandEncoderDescriptor { label: None, queue };
device.create_command_encoder(&hal_desc)
},
}
}
/// Add `encoder` back to the free pool.
pub(crate) fn release_encoder(&mut self, encoder: A::CommandEncoder) {
self.free_encoders.push(encoder);
}
/// Free the pool of command encoders.
///
/// This is only called when the `Device` is dropped.
pub(crate) fn dispose(self, device: &A::Device) {
resource_log!(
"CommandAllocator::dispose encoders {}",
self.free_encoders.len()
);
for cmd_encoder in self.free_encoders {
unsafe {
device.destroy_command_encoder(cmd_encoder);
}
}
}
}

View File

@ -1,3 +1,4 @@
mod allocator;
mod bind; mod bind;
mod bundle; mod bundle;
mod clear; mod clear;
@ -15,6 +16,7 @@ pub(crate) use self::clear::clear_texture;
pub use self::{ pub use self::{
bundle::*, clear::ClearError, compute::*, draw::*, query::*, render::*, transfer::*, bundle::*, clear::ClearError, compute::*, draw::*, query::*, render::*, transfer::*,
}; };
pub(crate) use allocator::CommandAllocator;
use self::memory_init::CommandBufferTextureMemoryActions; use self::memory_init::CommandBufferTextureMemoryActions;

View File

@ -361,7 +361,7 @@ impl<A: HalApi> LifetimeTracker<A> {
pub fn triage_submissions( pub fn triage_submissions(
&mut self, &mut self,
last_done: SubmissionIndex, last_done: SubmissionIndex,
command_allocator: &mut super::CommandAllocator<A>, command_allocator: &mut crate::command::CommandAllocator<A>,
) -> SmallVec<[SubmittedWorkDoneClosure; 1]> { ) -> SmallVec<[SubmittedWorkDoneClosure; 1]> {
profiling::scope!("triage_submissions"); profiling::scope!("triage_submissions");

View File

@ -4,7 +4,6 @@ use crate::{
hub::Hub, hub::Hub,
id::{BindGroupLayoutId, PipelineLayoutId}, id::{BindGroupLayoutId, PipelineLayoutId},
resource::{Buffer, BufferAccessError, BufferAccessResult, BufferMapOperation}, resource::{Buffer, BufferAccessError, BufferAccessResult, BufferMapOperation},
resource_log,
snatch::SnatchGuard, snatch::SnatchGuard,
Label, DOWNLEVEL_ERROR_MESSAGE, Label, DOWNLEVEL_ERROR_MESSAGE,
}; };
@ -377,59 +376,6 @@ fn map_buffer<A: HalApi>(
Ok(mapping.ptr) Ok(mapping.ptr)
} }
/// A pool of free [`wgpu_hal::CommandEncoder`]s, owned by a `Device`.
///
/// Each encoder in this list is in the "closed" state.
///
/// Since a raw [`CommandEncoder`][ce] is itself a pool for allocating
/// raw [`CommandBuffer`][cb]s, this is a pool of pools.
///
/// [ce]: wgpu_hal::CommandEncoder
/// [cb]: wgpu_hal::Api::CommandBuffer
pub(crate) struct CommandAllocator<A: HalApi> {
free_encoders: Vec<A::CommandEncoder>,
}
impl<A: HalApi> CommandAllocator<A> {
/// Return a fresh [`wgpu_hal::CommandEncoder`] in the "closed" state.
///
/// If we have free encoders in the pool, take one of those. Otherwise,
/// create a new one on `device`.
fn acquire_encoder(
&mut self,
device: &A::Device,
queue: &A::Queue,
) -> Result<A::CommandEncoder, hal::DeviceError> {
match self.free_encoders.pop() {
Some(encoder) => Ok(encoder),
None => unsafe {
let hal_desc = hal::CommandEncoderDescriptor { label: None, queue };
device.create_command_encoder(&hal_desc)
},
}
}
/// Add `encoder` back to the free pool.
fn release_encoder(&mut self, encoder: A::CommandEncoder) {
self.free_encoders.push(encoder);
}
/// Free the pool of command encoders.
///
/// This is only called when the `Device` is dropped.
fn dispose(self, device: &A::Device) {
resource_log!(
"CommandAllocator::dispose encoders {}",
self.free_encoders.len()
);
for cmd_encoder in self.free_encoders {
unsafe {
device.destroy_command_encoder(cmd_encoder);
}
}
}
}
#[derive(Clone, Debug, Error)] #[derive(Clone, Debug, Error)]
#[error("Device is invalid")] #[error("Device is invalid")]
pub struct InvalidDevice; pub struct InvalidDevice;

View File

@ -4,7 +4,7 @@ use crate::{
api_log, api_log,
command::{ command::{
extract_texture_selector, validate_linear_texture_data, validate_texture_copy_range, extract_texture_selector, validate_linear_texture_data, validate_texture_copy_range,
ClearError, CommandBuffer, CopySide, ImageCopyTexture, TransferError, ClearError, CommandAllocator, CommandBuffer, CopySide, ImageCopyTexture, TransferError,
}, },
conv, conv,
device::{life::ResourceMaps, DeviceError, WaitIdleError}, device::{life::ResourceMaps, DeviceError, WaitIdleError},
@ -258,7 +258,7 @@ impl<A: HalApi> PendingWrites<A> {
#[must_use] #[must_use]
fn post_submit( fn post_submit(
&mut self, &mut self,
command_allocator: &mut super::CommandAllocator<A>, command_allocator: &mut CommandAllocator<A>,
device: &A::Device, device: &A::Device,
queue: &A::Queue, queue: &A::Queue,
) -> Option<EncoderInFlight<A>> { ) -> Option<EncoderInFlight<A>> {

View File

@ -7,8 +7,8 @@ use crate::{
bgl, bgl,
life::{LifetimeTracker, WaitIdleError}, life::{LifetimeTracker, WaitIdleError},
queue::PendingWrites, queue::PendingWrites,
AttachmentData, CommandAllocator, DeviceLostInvocation, MissingDownlevelFlags, AttachmentData, DeviceLostInvocation, MissingDownlevelFlags, MissingFeatures,
MissingFeatures, RenderPassContext, CLEANUP_WAIT_MS, RenderPassContext, CLEANUP_WAIT_MS,
}, },
hal_api::HalApi, hal_api::HalApi,
hal_label, hal_label,
@ -97,7 +97,7 @@ pub struct Device<A: HalApi> {
pub(crate) zero_buffer: Option<A::Buffer>, pub(crate) zero_buffer: Option<A::Buffer>,
pub(crate) info: ResourceInfo<Device<A>>, pub(crate) info: ResourceInfo<Device<A>>,
pub(crate) command_allocator: Mutex<Option<CommandAllocator<A>>>, pub(crate) command_allocator: Mutex<Option<command::CommandAllocator<A>>>,
//Note: The submission index here corresponds to the last submission that is done. //Note: The submission index here corresponds to the last submission that is done.
pub(crate) active_submission_index: AtomicU64, //SubmissionIndex, pub(crate) active_submission_index: AtomicU64, //SubmissionIndex,
// NOTE: if both are needed, the `snatchable_lock` must be consistently acquired before the // NOTE: if both are needed, the `snatchable_lock` must be consistently acquired before the
@ -223,9 +223,7 @@ impl<A: HalApi> Device<A> {
let fence = let fence =
unsafe { raw_device.create_fence() }.map_err(|_| CreateDeviceError::OutOfMemory)?; unsafe { raw_device.create_fence() }.map_err(|_| CreateDeviceError::OutOfMemory)?;
let mut com_alloc = CommandAllocator { let mut com_alloc = command::CommandAllocator::new();
free_encoders: Vec::new(),
};
let pending_encoder = com_alloc let pending_encoder = com_alloc
.acquire_encoder(&raw_device, raw_queue) .acquire_encoder(&raw_device, raw_queue)
.map_err(|_| CreateDeviceError::OutOfMemory)?; .map_err(|_| CreateDeviceError::OutOfMemory)?;