Experimental command pool API

This commit is contained in:
Dzmitry Malyshau
2021-06-14 01:35:05 -04:00
parent 4eae5a38d0
commit c2bb2d5dfc
18 changed files with 541 additions and 264 deletions

View File

@@ -144,7 +144,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
// actual hal barrier & operation
let dst_barrier = dst_pending.map(|pending| pending.into_hal(dst_buffer));
let cmd_buf_raw = cmd_buf.raw.last_mut().unwrap();
let cmd_buf_raw = cmd_buf.encoder.open();
unsafe {
cmd_buf_raw.transition_buffers(dst_barrier);
cmd_buf_raw.fill_buffer(dst_raw, offset..end, 0);
@@ -246,7 +246,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
// actual hal barrier & operation
let dst_barrier = dst_pending.map(|pending| pending.into_hal(dst_texture));
let cmd_buf_raw = cmd_buf.raw.last_mut().unwrap();
let cmd_buf_raw = cmd_buf.encoder.open();
unsafe {
cmd_buf_raw.transition_textures(dst_barrier);
/*TODO: image clears

View File

@@ -270,7 +270,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
CommandBuffer::get_encoder_mut(&mut *cmd_buf_guard, encoder_id).map_pass_err(scope)?;
// will be reset to true if recording is done without errors
cmd_buf.status = CommandEncoderStatus::Error;
let raw = cmd_buf.raw.last_mut().unwrap();
let raw = cmd_buf.encoder.open();
#[cfg(feature = "trace")]
if let Some(ref mut list) = cmd_buf.commands {

View File

@@ -27,12 +27,10 @@ use crate::{
Label, Stored,
};
use hal::CommandBuffer as _;
use hal::{CommandBuffer as _, CommandPool as _};
use smallvec::SmallVec;
use thiserror::Error;
use std::thread;
const PUSH_CONSTANT_CLEAR_ARRAY: &[u32] = &[0_u32; 64];
#[derive(Debug)]
@@ -42,11 +40,43 @@ enum CommandEncoderStatus {
Error,
}
#[derive(Debug)]
struct CommandEncoder<A: hal::Api> {
pool: A::CommandPool,
list: Vec<A::CommandBuffer>,
is_open: bool,
label: String,
}
impl<A: hal::Api> CommandEncoder<A> {
fn close(&mut self) {
if self.is_open {
self.is_open = false;
unsafe { self.list.last_mut().unwrap().finish() };
}
}
fn open(&mut self) -> &mut A::CommandBuffer {
if !self.is_open {
self.is_open = true;
let hal_desc = hal::CommandBufferDescriptor {
label: Some(&self.label),
};
let raw = unsafe { self.pool.allocate(&hal_desc).unwrap() }; //TODO: handle this better
self.list.push(raw);
}
self.list.last_mut().unwrap()
}
}
pub struct BackedCommands<A: hal::Api> {
pub(crate) pool: A::CommandPool,
pub(crate) list: Vec<A::CommandBuffer>,
pub(crate) trackers: TrackerSet,
}
pub struct CommandBuffer<A: hal::Api> {
pub(crate) raw: Vec<A::CommandBuffer>,
encoder: CommandEncoder<A>,
status: CommandEncoderStatus,
recorded_thread_id: thread::ThreadId,
pub(crate) device_id: Stored<id::DeviceId>,
pub(crate) trackers: TrackerSet,
pub(crate) used_swap_chains: SmallVec<[Stored<id::SwapChainId>; 1]>,
@@ -56,24 +86,26 @@ pub struct CommandBuffer<A: hal::Api> {
support_fill_buffer_texture: bool,
#[cfg(feature = "trace")]
pub(crate) commands: Option<Vec<crate::device::trace::Command>>,
#[cfg(debug_assertions)]
pub(crate) label: String,
}
impl<A: HalApi> CommandBuffer<A> {
pub(crate) fn new(
raw: A::CommandBuffer,
pool: A::CommandPool,
device_id: Stored<id::DeviceId>,
limits: wgt::Limits,
downlevel: wgt::DownlevelCapabilities,
features: wgt::Features,
#[cfg(feature = "trace")] enable_tracing: bool,
#[cfg(debug_assertions)] label: &Label,
label: &Label,
) -> Self {
CommandBuffer {
raw: vec![raw],
encoder: CommandEncoder {
pool,
is_open: false,
list: Vec::new(),
label: crate::LabelHelpers::borrow_or_default(label).to_string(),
},
status: CommandEncoderStatus::Recording,
recorded_thread_id: thread::current().id(),
device_id,
trackers: TrackerSet::new(A::VARIANT),
used_swap_chains: Default::default(),
@@ -87,29 +119,6 @@ impl<A: HalApi> CommandBuffer<A> {
} else {
None
},
#[cfg(debug_assertions)]
label: crate::LabelHelpers::borrow_or_default(label).to_string(),
}
}
fn get_encoder_mut(
storage: &mut Storage<Self, id::CommandEncoderId>,
id: id::CommandEncoderId,
) -> Result<&mut Self, CommandEncoderError> {
match storage.get_mut(id) {
Ok(cmd_buf) => match cmd_buf.status {
CommandEncoderStatus::Recording => Ok(cmd_buf),
CommandEncoderStatus::Finished => Err(CommandEncoderError::NotRecording),
CommandEncoderStatus::Error => Err(CommandEncoderError::Invalid),
},
Err(_) => Err(CommandEncoderError::Invalid),
}
}
pub fn is_finished(&self) -> bool {
match self.status {
CommandEncoderStatus::Finished => true,
_ => false,
}
}
@@ -140,6 +149,37 @@ impl<A: HalApi> CommandBuffer<A> {
}
}
impl<A: hal::Api> CommandBuffer<A> {
fn get_encoder_mut(
storage: &mut Storage<Self, id::CommandEncoderId>,
id: id::CommandEncoderId,
) -> Result<&mut Self, CommandEncoderError> {
match storage.get_mut(id) {
Ok(cmd_buf) => match cmd_buf.status {
CommandEncoderStatus::Recording => Ok(cmd_buf),
CommandEncoderStatus::Finished => Err(CommandEncoderError::NotRecording),
CommandEncoderStatus::Error => Err(CommandEncoderError::Invalid),
},
Err(_) => Err(CommandEncoderError::Invalid),
}
}
pub fn is_finished(&self) -> bool {
match self.status {
CommandEncoderStatus::Finished => true,
_ => false,
}
}
pub(crate) fn into_baked(self) -> BackedCommands<A> {
BackedCommands {
pool: self.encoder.pool,
list: self.encoder.list,
trackers: self.trackers,
}
}
}
impl<A: hal::Api> crate::hub::Resource for CommandBuffer<A> {
const TYPE: &'static str = "CommandBuffer";
@@ -148,10 +188,7 @@ impl<A: hal::Api> crate::hub::Resource for CommandBuffer<A> {
}
fn label(&self) -> &str {
#[cfg(debug_assertions)]
return &self.label;
#[cfg(not(debug_assertions))]
return "";
&self.encoder.label
}
}
@@ -239,6 +276,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
let error = match CommandBuffer::get_encoder_mut(&mut *cmd_buf_guard, encoder_id) {
Ok(cmd_buf) => {
cmd_buf.encoder.close();
cmd_buf.status = CommandEncoderStatus::Finished;
// stop tracking the swapchain image, if used
for sc_id in cmd_buf.used_swap_chains.iter() {
@@ -269,7 +307,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
let (mut cmd_buf_guard, _) = hub.command_buffers.write(&mut token);
let cmd_buf = CommandBuffer::get_encoder_mut(&mut *cmd_buf_guard, encoder_id)?;
let cmd_buf_raw = cmd_buf.raw.last_mut().unwrap();
let cmd_buf_raw = cmd_buf.encoder.open();
unsafe {
cmd_buf_raw.begin_debug_marker(label);
@@ -289,7 +327,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
let (mut cmd_buf_guard, _) = hub.command_buffers.write(&mut token);
let cmd_buf = CommandBuffer::get_encoder_mut(&mut *cmd_buf_guard, encoder_id)?;
let cmd_buf_raw = cmd_buf.raw.last_mut().unwrap();
let cmd_buf_raw = cmd_buf.encoder.open();
unsafe {
cmd_buf_raw.insert_debug_marker(label);
@@ -308,7 +346,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
let (mut cmd_buf_guard, _) = hub.command_buffers.write(&mut token);
let cmd_buf = CommandBuffer::get_encoder_mut(&mut *cmd_buf_guard, encoder_id)?;
let cmd_buf_raw = cmd_buf.raw.last_mut().unwrap();
let cmd_buf_raw = cmd_buf.encoder.open();
unsafe {
cmd_buf_raw.end_debug_marker();

View File

@@ -288,7 +288,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
let (query_set_guard, _) = hub.query_sets.read(&mut token);
let cmd_buf = CommandBuffer::get_encoder_mut(&mut cmd_buf_guard, command_encoder_id)?;
let cmd_buf_raw = cmd_buf.raw.last_mut().unwrap();
let cmd_buf_raw = cmd_buf.encoder.open();
#[cfg(feature = "trace")]
if let Some(ref mut list) = cmd_buf.commands {
@@ -329,7 +329,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
let (buffer_guard, _) = hub.buffers.read(&mut token);
let cmd_buf = CommandBuffer::get_encoder_mut(&mut cmd_buf_guard, command_encoder_id)?;
let cmd_buf_raw = cmd_buf.raw.last_mut().unwrap();
let cmd_buf_raw = cmd_buf.encoder.open();
#[cfg(feature = "trace")]
if let Some(ref mut list) = cmd_buf.commands {

View File

@@ -24,7 +24,7 @@ use crate::{
};
use arrayvec::ArrayVec;
use hal::{CommandBuffer as _, Device as _};
use hal::{CommandBuffer as _, CommandPool as _};
use thiserror::Error;
use wgt::{
BufferAddress, BufferSize, BufferUsage, Color, IndexFormat, InputStepMode, TextureUsage,
@@ -846,12 +846,14 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
let (device_guard, mut token) = hub.devices.read(&mut token);
let (cmd_buf_raw, trackers, query_reset_state) = {
let (pass_raw, trackers, query_reset_state) = {
// read-only lock guard
let (mut cmb_guard, mut token) = hub.command_buffers.write(&mut token);
let cmd_buf =
CommandBuffer::get_encoder_mut(&mut *cmb_guard, encoder_id).map_pass_err(scope)?;
// close everything while the new command encoder is filled
cmd_buf.encoder.close();
// will be reset to true if recording is done without errors
cmd_buf.status = CommandEncoderStatus::Error;
@@ -866,9 +868,10 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
let device = &device_guard[cmd_buf.device_id.value];
let mut raw = unsafe {
device
.raw
.create_command_buffer(&hal::CommandBufferDescriptor { label: base.label })
cmd_buf
.encoder
.pool
.allocate(&hal::CommandBufferDescriptor { label: base.label })
.unwrap() //TODO: handle this better
};
@@ -1736,6 +1739,9 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
log::trace!("Merging {:?} with the render pass", encoder_id);
let (trackers, used_swapchain) =
info.finish(&mut raw, &*texture_guard).map_pass_err(scope)?;
unsafe {
raw.finish();
}
cmd_buf.status = CommandEncoderStatus::Recording;
cmd_buf.used_swap_chains.extend(used_swapchain);
(raw, trackers, query_reset_state)
@@ -1748,29 +1754,28 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
let cmd_buf =
CommandBuffer::get_encoder_mut(&mut *cmb_guard, encoder_id).map_pass_err(scope)?;
let last_cmd_buf = cmd_buf.raw.last_mut().unwrap();
{
let transit = cmd_buf.encoder.open();
query_reset_state
.reset_queries(
transit,
&query_set_guard,
cmd_buf.device_id.value.0.backend(),
)
.map_err(RenderCommandError::InvalidQuerySet)
.map_pass_err(PassErrorScope::QueryReset)?;
query_reset_state
.reset_queries(
last_cmd_buf,
&query_set_guard,
cmd_buf.device_id.value.0.backend(),
)
.map_err(RenderCommandError::InvalidQuerySet)
.map_pass_err(PassErrorScope::QueryReset)?;
super::CommandBuffer::insert_barriers(
last_cmd_buf,
&mut cmd_buf.trackers,
&trackers.buffers,
&trackers.textures,
&*buffer_guard,
&*texture_guard,
);
unsafe {
last_cmd_buf.finish();
super::CommandBuffer::insert_barriers(
transit,
&mut cmd_buf.trackers,
&trackers.buffers,
&trackers.textures,
&*buffer_guard,
&*texture_guard,
);
}
cmd_buf.raw.push(cmd_buf_raw);
cmd_buf.encoder.close();
cmd_buf.encoder.list.push(pass_raw);
Ok(())
}

View File

@@ -431,7 +431,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
dst_offset: destination_offset,
size: wgt::BufferSize::new(size).unwrap(),
};
let cmd_buf_raw = cmd_buf.raw.last_mut().unwrap();
let cmd_buf_raw = cmd_buf.encoder.open();
unsafe {
cmd_buf_raw.transition_buffers(src_barrier.into_iter().chain(dst_barrier));
cmd_buf_raw.copy_buffer_to_buffer(src_raw, dst_raw, iter::once(region));
@@ -450,6 +450,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
let hub = A::hub(self);
let mut token = Token::root();
let (mut cmd_buf_guard, mut token) = hub.command_buffers.write(&mut token);
let cmd_buf = CommandBuffer::get_encoder_mut(&mut *cmd_buf_guard, command_encoder_id)?;
let (buffer_guard, mut token) = hub.buffers.read(&mut token);
@@ -554,7 +555,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
depth_or_array_layers: copy_size.depth_or_array_layers,
},
};
let cmd_buf_raw = cmd_buf.raw.last_mut().unwrap();
let cmd_buf_raw = cmd_buf.encoder.open();
unsafe {
cmd_buf_raw.transition_buffers(src_barriers);
cmd_buf_raw.transition_textures(dst_barriers);
@@ -574,6 +575,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
let hub = A::hub(self);
let mut token = Token::root();
let (mut cmd_buf_guard, mut token) = hub.command_buffers.write(&mut token);
let cmd_buf = CommandBuffer::get_encoder_mut(&mut *cmd_buf_guard, command_encoder_id)?;
let (buffer_guard, mut token) = hub.buffers.read(&mut token);
@@ -682,7 +684,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
depth_or_array_layers: copy_size.depth_or_array_layers,
},
};
let cmd_buf_raw = cmd_buf.raw.last_mut().unwrap();
let cmd_buf_raw = cmd_buf.encoder.open();
unsafe {
cmd_buf_raw.transition_buffers(dst_barriers);
cmd_buf_raw.transition_textures(src_barriers);
@@ -805,7 +807,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
depth_or_array_layers: copy_size.depth_or_array_layers,
},
};
let cmd_buf_raw = cmd_buf.raw.last_mut().unwrap();
let cmd_buf_raw = cmd_buf.encoder.open();
unsafe {
cmd_buf_raw.transition_textures(barriers.into_iter());
cmd_buf_raw.copy_texture_to_texture(

View File

@@ -5,7 +5,10 @@
#[cfg(feature = "trace")]
use crate::device::trace;
use crate::{
device::{queue::TempResource, DeviceError},
device::{
queue::{PoolExecution, TempResource},
DeviceError,
},
hub::{GlobalIdentityHandlerFactory, HalApi, Hub, Token},
id, resource,
track::TrackerSet,
@@ -165,6 +168,7 @@ struct ActiveSubmission<A: hal::Api> {
index: SubmissionIndex,
last_resources: NonReferencedResources<A>,
mapped: Vec<id::Valid<id::BufferId>>,
pool_executions: Vec<PoolExecution<A>>,
}
#[derive(Clone, Debug, Error)]
@@ -221,6 +225,7 @@ impl<A: hal::Api> LifetimeTracker<A> {
index: SubmissionIndex,
new_suspects: &SuspectedResources,
temp_resources: impl Iterator<Item = TempResource<A>>,
pool_executions: Vec<PoolExecution<A>>,
) {
let mut last_resources = NonReferencedResources::new();
for res in temp_resources {
@@ -246,6 +251,7 @@ impl<A: hal::Api> LifetimeTracker<A> {
index,
last_resources,
mapped: Vec::new(),
pool_executions,
});
}
@@ -254,7 +260,11 @@ impl<A: hal::Api> LifetimeTracker<A> {
}
/// Returns the last submission index that is done.
pub fn triage_submissions(&mut self, last_done: SubmissionIndex) {
pub fn triage_submissions(
&mut self,
last_done: SubmissionIndex,
pool_allocator: &Mutex<super::PoolAllocator<A>>,
) {
profiling::scope!("triage_submissions");
//TODO: enable when `is_sorted_by_key` is stable
@@ -269,6 +279,10 @@ impl<A: hal::Api> LifetimeTracker<A> {
log::trace!("Active submission {} is done", a.index);
self.free_resources.extend(a.last_resources);
self.ready_to_map.extend(a.mapped);
for pool_exec in a.pool_executions {
let cmd_pool = unsafe { pool_exec.finish() };
pool_allocator.lock().release_pool(cmd_pool);
}
}
}

View File

@@ -16,7 +16,7 @@ use crate::{
use arrayvec::ArrayVec;
use copyless::VecHelper as _;
use hal::{CommandBuffer as _, Device as _};
use hal::{CommandBuffer as _, CommandPool as _, Device as _};
use parking_lot::{Mutex, MutexGuard};
use thiserror::Error;
use wgt::{BufferAddress, TextureFormat, TextureViewDimension};
@@ -180,6 +180,30 @@ fn fire_map_callbacks<I: IntoIterator<Item = BufferMapPendingCallback>>(callback
}
}
struct PoolAllocator<A: hal::Api> {
free_pools: Vec<A::CommandPool>,
}
impl<A: hal::Api> PoolAllocator<A> {
fn acquire_pool(
&mut self,
device: &A::Device,
queue: &A::Queue,
) -> Result<A::CommandPool, hal::DeviceError> {
match self.free_pools.pop() {
Some(pool) => Ok(pool),
None => unsafe {
let hal_desc = hal::CommandPoolDescriptor { label: None, queue };
device.create_command_pool(&hal_desc)
},
}
}
fn release_pool(&mut self, pool: A::CommandPool) {
self.free_pools.push(pool);
}
}
/// Structure describing a logical device. Some members are internally mutable,
/// stored behind mutexes.
/// TODO: establish clear order of locking for these:
@@ -199,6 +223,7 @@ pub struct Device<A: hal::Api> {
//desc_allocator: Mutex<descriptor::DescriptorAllocator<A>>,
//Note: The submission index here corresponds to the last submission that is done.
pub(crate) life_guard: LifeGuard,
pool_allocator: Mutex<PoolAllocator<A>>,
pub(crate) active_submission_index: SubmissionIndex,
fence: A::Fence,
/// Has to be locked temporarily only (locked last)
@@ -240,11 +265,20 @@ impl<A: HalApi> Device<A> {
let fence =
unsafe { open.device.create_fence() }.map_err(|_| CreateDeviceError::OutOfMemory)?;
let mut palloc = PoolAllocator {
free_pools: Vec::new(),
};
let pending_pool = palloc
.acquire_pool(&open.device, &open.queue)
.map_err(|_| CreateDeviceError::OutOfMemory)?;
let pending_writes = queue::PendingWrites::new(pending_pool);
Ok(Self {
raw: open.device,
adapter_id,
queue: open.queue,
life_guard: LifeGuard::new("<device>"),
pool_allocator: Mutex::new(palloc),
active_submission_index: 0,
fence,
trackers: Mutex::new(TrackerSet::new(A::VARIANT)),
@@ -268,7 +302,7 @@ impl<A: HalApi> Device<A> {
limits: desc.limits.clone(),
features: desc.features,
downlevel,
pending_writes: queue::PendingWrites::new(),
pending_writes,
})
}
@@ -329,7 +363,7 @@ impl<A: HalApi> Device<A> {
}
};
life_tracker.triage_submissions(last_done_index);
life_tracker.triage_submissions(last_done_index, &self.pool_allocator);
let callbacks = life_tracker.handle_mapping(hub, &self.raw, &self.trackers, token);
life_tracker.cleanup(&self.raw);
@@ -2179,7 +2213,8 @@ impl<A: HalApi> Device<A> {
.wait(&self.fence, submission_index, !0)
.map_err(DeviceError::from)?
};
self.lock_life(token).triage_submissions(submission_index);
self.lock_life(token)
.triage_submissions(submission_index, &self.pool_allocator);
}
Ok(())
}
@@ -2241,6 +2276,18 @@ impl<A: hal::Api> Device<A> {
}
}
pub(crate) fn destroy_command_buffer(&self, cmd_buf: command::CommandBuffer<A>) {
let mut baked = cmd_buf.into_baked();
for raw in baked.list {
unsafe {
baked.pool.free(raw);
}
}
unsafe {
self.raw.destroy_command_pool(baked.pool);
}
}
/// Wait for idle and remove resources that we can, before we die.
pub(crate) fn prepare_to_die(&mut self) {
let mut life_tracker = self.life_tracker.lock();
@@ -2248,7 +2295,7 @@ impl<A: hal::Api> Device<A> {
if let Err(error) = unsafe { self.raw.wait(&self.fence, current_index, CLEANUP_WAIT_MS) } {
log::error!("failed to wait for the device: {:?}", error);
}
life_tracker.triage_submissions(current_index);
life_tracker.triage_submissions(current_index, &self.pool_allocator);
life_tracker.cleanup(&self.raw);
}
@@ -3430,33 +3477,28 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
Ok(device) => device,
Err(_) => break DeviceError::Invalid,
};
let dev_stored = Stored {
value: id::Valid(device_id),
ref_count: device.life_guard.add_ref(),
};
let cmd_buf_result = unsafe {
device
.raw
.create_command_buffer(&hal::CommandBufferDescriptor {
label: desc.label.borrow_option(),
})
let hal_desc = hal::CommandPoolDescriptor {
label: None,
queue: &device.queue,
};
let raw = match cmd_buf_result {
Ok(raw) => raw,
Err(error) => break DeviceError::from(error),
let pool = match unsafe { device.raw.create_command_pool(&hal_desc) } {
Ok(pool) => pool,
Err(_) => break DeviceError::OutOfMemory,
};
let command_buffer = command::CommandBuffer::new(
raw,
pool,
dev_stored,
device.limits.clone(),
device.downlevel,
device.features,
#[cfg(feature = "trace")]
device.trace.is_some(),
#[cfg(debug_assertions)]
&desc.label,
);

View File

@@ -18,11 +18,19 @@ use crate::{
FastHashMap, FastHashSet,
};
use hal::{CommandBuffer as _, Device as _, Queue as _};
use hal::{CommandBuffer as _, CommandPool as _, Device as _, Queue as _};
use parking_lot::Mutex;
use smallvec::SmallVec;
use std::{iter, num::NonZeroU32, ops::Range, ptr};
use std::{iter, mem, num::NonZeroU32, ops::Range, ptr};
use thiserror::Error;
/// Number of command buffers that we generate from the same pool
/// for the write_xxx commands, before the pool is recycled.
///
/// If we don't stop at some point, the pool will grow forever,
/// without a concrete moment of when it can be cleared.
const WRITE_COMMAND_BUFFERS_PER_POOL: usize = 64;
struct StagingData<A: hal::Api> {
buffer: A::Buffer,
cmdbuf: A::CommandBuffer,
@@ -52,30 +60,52 @@ pub enum TempResource<A: hal::Api> {
Texture(A::Texture),
}
/// A queue execution for a particular command pool.
pub(super) struct PoolExecution<A: hal::Api> {
cmd_pool: A::CommandPool,
cmd_buffers: Vec<A::CommandBuffer>,
}
impl<A: hal::Api> PoolExecution<A> {
pub(super) unsafe fn finish(mut self) -> A::CommandPool {
for cmd_buf in self.cmd_buffers {
self.cmd_pool.free(cmd_buf);
}
self.cmd_pool
}
}
#[derive(Debug)]
pub(crate) struct PendingWrites<A: hal::Api> {
pub command_pool: A::CommandPool,
pub command_buffer: Option<A::CommandBuffer>,
pub temp_resources: Vec<TempResource<A>>,
pub dst_buffers: FastHashSet<id::BufferId>,
pub dst_textures: FastHashSet<id::TextureId>,
pub executing_command_buffers: Vec<A::CommandBuffer>,
}
impl<A: hal::Api> PendingWrites<A> {
pub fn new() -> Self {
pub fn new(command_pool: A::CommandPool) -> Self {
Self {
command_pool,
command_buffer: None,
temp_resources: Vec::new(),
dst_buffers: FastHashSet::default(),
dst_textures: FastHashSet::default(),
executing_command_buffers: Vec::new(),
}
}
pub fn dispose(self, device: &A::Device) {
if let Some(cmd_buf) = self.command_buffer {
unsafe {
device.destroy_command_buffer(cmd_buf);
}
pub fn dispose(mut self, device: &A::Device) {
if let Some(raw) = self.command_buffer {
unsafe { self.command_pool.free(raw) };
}
for raw in self.executing_command_buffers {
unsafe { self.command_pool.free(raw) };
}
unsafe { device.destroy_command_pool(self.command_pool) };
for resource in self.temp_resources {
match resource {
TempResource::Buffer(buffer) => unsafe {
@@ -99,28 +129,48 @@ impl<A: hal::Api> PendingWrites<A> {
}
#[must_use]
fn finish(&mut self) -> Option<A::CommandBuffer> {
fn pre_submit(&mut self) -> Option<&A::CommandBuffer> {
self.dst_buffers.clear();
self.dst_textures.clear();
self.command_buffer.take().map(|mut cmd_buf| unsafe {
cmd_buf.finish();
cmd_buf
})
let mut cmd_buf = self.command_buffer.take()?;
unsafe { cmd_buf.finish() };
self.executing_command_buffers.push(cmd_buf);
self.executing_command_buffers.last()
}
fn create_cmd_buf(device: &A::Device) -> A::CommandBuffer {
#[must_use]
fn post_submit(
&mut self,
pool_alloc: &Mutex<super::PoolAllocator<A>>,
device: &A::Device,
queue: &A::Queue,
) -> Option<PoolExecution<A>> {
assert!(self.command_buffer.is_none());
if self.executing_command_buffers.len() >= WRITE_COMMAND_BUFFERS_PER_POOL {
let new_pool = pool_alloc.lock().acquire_pool(device, queue).unwrap();
Some(PoolExecution {
cmd_pool: mem::replace(&mut self.command_pool, new_pool),
cmd_buffers: mem::take(&mut self.executing_command_buffers),
})
} else {
None
}
}
fn create_cmd_buf(&mut self) -> A::CommandBuffer {
unsafe {
device
.create_command_buffer(&hal::CommandBufferDescriptor {
self.command_pool
.allocate(&hal::CommandBufferDescriptor {
label: Some("_PendingWrites"),
})
.unwrap()
}
}
fn borrow_cmd_buf(&mut self, device: &A::Device) -> &mut A::CommandBuffer {
fn borrow_cmd_buf(&mut self) -> &mut A::CommandBuffer {
if self.command_buffer.is_none() {
self.command_buffer = Some(Self::create_cmd_buf(device));
let raw = self.create_cmd_buf();
self.command_buffer = Some(raw);
}
self.command_buffer.as_mut().unwrap()
}
@@ -161,7 +211,7 @@ impl RequiredBufferInits {
impl<A: hal::Api> super::Device<A> {
pub fn borrow_pending_writes(&mut self) -> &mut A::CommandBuffer {
self.pending_writes.borrow_cmd_buf(&self.raw)
self.pending_writes.borrow_cmd_buf()
}
fn prepare_stage(&mut self, size: wgt::BufferAddress) -> Result<StagingData<A>, DeviceError> {
@@ -176,7 +226,7 @@ impl<A: hal::Api> super::Device<A> {
let cmdbuf = match self.pending_writes.command_buffer.take() {
Some(cmdbuf) => cmdbuf,
None => PendingWrites::<A>::create_cmd_buf(&self.raw),
None => self.pending_writes.create_cmd_buf(),
};
Ok(StagingData { buffer, cmdbuf })
}
@@ -190,7 +240,7 @@ impl<A: hal::Api> super::Device<A> {
.dst_buffers
.extend(required_buffer_inits.map.keys());
let cmd_buf = self.pending_writes.borrow_cmd_buf(&self.raw);
let cmd_buf = self.pending_writes.borrow_cmd_buf();
let mut trackers = self.trackers.lock();
for (buffer_id, mut ranges) in required_buffer_inits.map.drain() {
@@ -566,10 +616,10 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
let device = device_guard
.get_mut(queue_id)
.map_err(|_| DeviceError::Invalid)?;
let pending_write_command_buffer = device.pending_writes.finish();
device.temp_suspected.clear();
device.active_submission_index += 1;
let submit_index = device.active_submission_index;
let mut active_executions = Vec::new();
{
let mut signal_swapchain_semaphores = SmallVec::<[_; 1]>::new();
@@ -599,9 +649,12 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
// finish all the command buffers first
for &cmb_id in command_buffer_ids {
let cmdbuf = match command_buffer_guard.get_mut(cmb_id) {
Ok(cmdbuf) => cmdbuf,
Err(_) => continue,
let mut cmdbuf = match hub
.command_buffers
.unregister_locked(cmb_id, &mut *command_buffer_guard)
{
Some(cmdbuf) => cmdbuf,
None => continue,
};
#[cfg(feature = "trace")]
if let Some(ref trace) = device.trace {
@@ -611,6 +664,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
));
}
if !cmdbuf.is_finished() {
device.destroy_command_buffer(cmdbuf);
continue;
}
@@ -695,33 +749,36 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
}
}
unsafe {
// the last buffer was open, closing now
cmdbuf.raw.last_mut().unwrap().finish();
}
let mut baked = cmdbuf.into_baked();
// execute resource transitions
let transit_desc = hal::CommandBufferDescriptor {
label: Some("_Transit"),
};
let mut transit = unsafe {
device
.raw
.create_command_buffer(&hal::CommandBufferDescriptor {
label: Some("_Transit"),
})
baked
.pool
.allocate(&transit_desc)
.map_err(DeviceError::from)?
};
log::trace!("Stitching command buffer {:?} before submission", cmb_id);
trackers.merge_extend_stateless(&cmdbuf.trackers);
trackers.merge_extend_stateless(&baked.trackers);
CommandBuffer::insert_barriers(
&mut transit,
&mut *trackers,
&cmdbuf.trackers.buffers,
&cmdbuf.trackers.textures,
&baked.trackers.buffers,
&baked.trackers.textures,
&*buffer_guard,
&*texture_guard,
);
unsafe {
transit.finish();
}
cmdbuf.raw.insert(0, transit);
baked.list.insert(0, transit);
active_executions.push(PoolExecution {
cmd_pool: baked.pool,
cmd_buffers: baked.list,
});
}
log::trace!("Device after submission {}: {:#?}", submit_index, trackers);
@@ -732,25 +789,24 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
}
}
//Note: we could technically avoid the heap Vec here
let mut command_buffers = Vec::new();
command_buffers.extend(pending_write_command_buffer);
for &cmd_buf_id in command_buffer_ids.iter() {
match command_buffer_guard.get_mut(cmd_buf_id) {
Ok(cmd_buf) if cmd_buf.is_finished() => {
command_buffers.extend(cmd_buf.raw.drain(..));
}
_ => {}
}
}
let super::Device {
ref mut pending_writes,
ref mut queue,
ref mut fence,
..
} = *device;
let refs = pending_writes
.pre_submit()
.into_iter()
.chain(
active_executions
.iter()
.flat_map(|pool_execution| pool_execution.cmd_buffers.iter()),
)
.collect::<Vec<_>>();
unsafe {
device
.queue
.submit(
command_buffers.into_iter(),
Some((&mut device.fence, submit_index)),
)
queue
.submit(&refs, Some((fence, submit_index)))
.map_err(DeviceError::from)?;
}
}
@@ -762,10 +818,18 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
};
profiling::scope!("cleanup");
if let Some(pending_execution) = device.pending_writes.post_submit(
&device.pool_allocator,
&device.raw,
&device.queue,
) {
active_executions.push(pending_execution);
}
super::Device::lock_life_internal(&device.life_tracker, &mut token).track_submission(
submit_index,
&device.temp_suspected,
device.pending_writes.temp_resources.drain(..),
active_executions,
);
callbacks

View File

@@ -626,11 +626,7 @@ impl<A: HalApi, F: GlobalIdentityHandlerFactory> Hub<A, F> {
for element in self.command_buffers.data.write().map.drain(..) {
if let Element::Occupied(command_buffer, _) = element {
let device = &devices[command_buffer.device_id.value];
for raw in command_buffer.raw {
unsafe {
device.raw.destroy_command_buffer(raw);
}
}
device.destroy_command_buffer(command_buffer);
}
}
for element in self.bind_groups.data.write().map.drain(..) {

View File

@@ -1,6 +1,9 @@
extern crate wgpu_hal as hal;
use hal::{Adapter as _, CommandBuffer as _, Device as _, Instance as _, Queue as _, Surface as _};
use hal::{
Adapter as _, CommandBuffer as _, CommandPool as _, Device as _, Instance as _, Queue as _,
Surface as _,
};
use std::{borrow::Borrow, iter, mem, num::NonZeroU32, ptr, time::Instant};
@@ -26,6 +29,11 @@ struct Locals {
_pad: u32,
}
struct UsedResources<A: hal::Api> {
view: A::TextureView,
cmd_buf: A::CommandBuffer,
}
#[allow(dead_code)]
struct Example<A: hal::Api> {
instance: A::Instance,
@@ -45,7 +53,8 @@ struct Example<A: hal::Api> {
view: A::TextureView,
fence: A::Fence,
fence_value: hal::FenceValue,
old_views: Vec<(hal::FenceValue, A::TextureView)>,
cmd_pool: A::CommandPool,
old_resources: Vec<(hal::FenceValue, UsedResources<A>)>,
extent: [u32; 2],
start: Instant,
}
@@ -237,10 +246,15 @@ impl<A: hal::Api> Example<A> {
};
let texture = unsafe { device.create_texture(&texture_desc).unwrap() };
let cmd_pool_desc = hal::CommandPoolDescriptor {
label: None,
queue: &queue,
};
let mut cmd_pool = unsafe { device.create_command_pool(&cmd_pool_desc).unwrap() };
let init_cmd_desc = hal::CommandBufferDescriptor {
label: Some("init"),
};
let mut init_cmd = unsafe { device.create_command_buffer(&init_cmd_desc).unwrap() };
let mut init_cmd = unsafe { cmd_pool.allocate(&init_cmd_desc).unwrap() };
{
let buffer_barrier = hal::BufferBarrier {
buffer: &staging_buffer,
@@ -397,11 +411,10 @@ impl<A: hal::Api> Example<A> {
let fence = unsafe {
let mut fence = device.create_fence().unwrap();
init_cmd.finish();
queue
.submit(iter::once(init_cmd), Some((&mut fence, 1)))
.unwrap();
queue.submit(&[&init_cmd], Some((&mut fence, 1))).unwrap();
device.wait(&fence, 1, !0).unwrap();
device.destroy_buffer(staging_buffer);
cmd_pool.free(init_cmd);
fence
};
@@ -421,7 +434,8 @@ impl<A: hal::Api> Example<A> {
sampler,
texture,
view,
old_views: Vec::new(),
old_resources: Vec::new(),
cmd_pool,
fence,
fence_value: 1,
extent: [window_size.0, window_size.1],
@@ -494,8 +508,8 @@ impl<A: hal::Api> Example<A> {
}
let mut cmd_buf = unsafe {
self.device
.create_command_buffer(&hal::CommandBufferDescriptor {
self.cmd_pool
.allocate(&hal::CommandBufferDescriptor {
label: Some("frame"),
})
.unwrap()
@@ -550,20 +564,33 @@ impl<A: hal::Api> Example<A> {
self.fence_value += 1;
let last_done = unsafe { self.device.get_fence_value(&self.fence).unwrap() };
self.old_views.retain(|&(value, _)| value <= last_done);
self.old_views.push((self.fence_value, surface_tex_view));
for i in (0..self.old_resources.len()).rev() {
if self.old_resources[i].0 <= last_done {
let (_, old) = self.old_resources.swap_remove(i);
unsafe {
self.device.destroy_texture_view(old.view);
self.cmd_pool.free(old.cmd_buf);
}
//TODO: clear the pool from time to time
}
}
unsafe {
cmd_buf.end_render_pass();
cmd_buf.finish();
self.queue
.submit(
iter::once(cmd_buf),
Some((&mut self.fence, self.fence_value)),
)
.submit(&[&cmd_buf], Some((&mut self.fence, self.fence_value)))
.unwrap();
self.queue.present(&mut self.surface, surface_tex).unwrap();
}
self.old_resources.push((
self.fence_value,
UsedResources {
view: surface_tex_view,
cmd_buf,
},
));
}
}

View File

@@ -15,9 +15,10 @@ impl crate::Api for Api {
type Instance = Context;
type Surface = Context;
type Adapter = Context;
type Queue = Context;
type Device = Context;
type Queue = Context;
type CommandPool = Context;
type CommandBuffer = Encoder;
type Buffer = Resource;
@@ -89,9 +90,9 @@ impl crate::Adapter<Api> for Context {
}
impl crate::Queue<Api> for Context {
unsafe fn submit<I>(
unsafe fn submit(
&mut self,
command_buffers: I,
command_buffers: &[&Encoder],
signal_fence: Option<(&mut Resource, crate::FenceValue)>,
) -> DeviceResult<()> {
Ok(())
@@ -105,6 +106,14 @@ impl crate::Queue<Api> for Context {
}
}
impl crate::CommandPool<Api> for Context {
unsafe fn allocate(&mut self, desc: &crate::CommandBufferDescriptor) -> DeviceResult<Encoder> {
Ok(Encoder)
}
unsafe fn free(&mut self, cmd_buf: Encoder) {}
unsafe fn clear(&mut self) {}
}
impl crate::Device<Api> for Context {
unsafe fn create_buffer(&self, desc: &crate::BufferDescriptor) -> DeviceResult<Resource> {
Ok(Resource)
@@ -140,13 +149,13 @@ impl crate::Device<Api> for Context {
}
unsafe fn destroy_sampler(&self, sampler: Resource) {}
unsafe fn create_command_buffer(
unsafe fn create_command_pool(
&self,
desc: &crate::CommandBufferDescriptor,
) -> DeviceResult<Encoder> {
Ok(Encoder)
desc: &crate::CommandPoolDescriptor<Api>,
) -> DeviceResult<Context> {
Ok(Context)
}
unsafe fn destroy_command_buffer(&self, cmd_buf: Encoder) {}
unsafe fn destroy_command_pool(&self, pool: Context) {}
unsafe fn create_bind_group_layout(
&self,

View File

@@ -126,7 +126,9 @@ pub trait Api: Clone + Sized {
type Surface: Surface<Self>;
type Adapter: Adapter<Self>;
type Device: Device<Self>;
type Queue: Queue<Self>;
type CommandPool: CommandPool<Self>;
type CommandBuffer: CommandBuffer<Self>;
type Buffer: fmt::Debug + Send + Sync + 'static;
@@ -221,12 +223,11 @@ pub trait Device<A: Api>: Send + Sync {
unsafe fn create_sampler(&self, desc: &SamplerDescriptor) -> Result<A::Sampler, DeviceError>;
unsafe fn destroy_sampler(&self, sampler: A::Sampler);
//TODO: consider making DX12-style command pools
unsafe fn create_command_buffer(
unsafe fn create_command_pool(
&self,
desc: &CommandBufferDescriptor,
) -> Result<A::CommandBuffer, DeviceError>;
unsafe fn destroy_command_buffer(&self, cmd_buf: A::CommandBuffer);
desc: &CommandPoolDescriptor<A>,
) -> Result<A::CommandPool, DeviceError>;
unsafe fn destroy_command_pool(&self, pool: A::CommandPool);
unsafe fn create_bind_group_layout(
&self,
@@ -281,13 +282,17 @@ pub trait Device<A: Api>: Send + Sync {
}
pub trait Queue<A: Api>: Send + Sync {
unsafe fn submit<I>(
/// Submits the command buffers for execution on GPU.
///
/// Valid usage:
/// - all of the command buffers were created from command pools
/// that are associated with this queue.
/// - all of the command buffers had `CommadBuffer::finish()` called.
unsafe fn submit(
&mut self,
command_buffers: I,
command_buffers: &[&A::CommandBuffer],
signal_fence: Option<(&mut A::Fence, FenceValue)>,
) -> Result<(), DeviceError>
where
I: Iterator<Item = A::CommandBuffer>;
) -> Result<(), DeviceError>;
unsafe fn present(
&mut self,
surface: &mut A::Surface,
@@ -295,6 +300,19 @@ pub trait Queue<A: Api>: Send + Sync {
) -> Result<(), SurfaceError>;
}
pub trait CommandPool<A: Api>: Send + Sync {
unsafe fn allocate(
&mut self,
desc: &CommandBufferDescriptor,
) -> Result<A::CommandBuffer, DeviceError>;
unsafe fn free(&mut self, cmd_buf: A::CommandBuffer);
/// Reclaims all resources that are allocated for this pool.
///
/// Valid usage:
/// - there are no allocated command buffers created from this pool.
unsafe fn clear(&mut self);
}
pub trait CommandBuffer<A: Api>: Send + Sync {
unsafe fn finish(&mut self);
@@ -797,6 +815,12 @@ pub struct BindGroupDescriptor<'a, A: Api> {
}
#[derive(Clone, Debug)]
pub struct CommandPoolDescriptor<'a, A: Api> {
pub label: Label<'a>,
pub queue: &'a A::Queue,
}
#[derive(Debug)]
pub struct CommandBufferDescriptor<'a> {
pub label: Label<'a>,
}

View File

@@ -1,5 +1,6 @@
use mtl::{MTLFeatureSet, MTLGPUFamily, MTLLanguageVersion};
use objc::{class, msg_send, sel, sel_impl};
use parking_lot::Mutex;
use std::{sync::Arc, thread};
@@ -17,13 +18,18 @@ impl crate::Adapter<super::Api> for super::Adapter {
&self,
features: wgt::Features,
) -> Result<crate::OpenDevice<super::Api>, crate::DeviceError> {
let queue = self
.shared
.device
.lock()
.new_command_queue_with_max_command_buffer_count(5);
Ok(crate::OpenDevice {
device: super::Device {
shared: Arc::clone(&self.shared),
features,
},
queue: super::Queue {
shared: Arc::clone(&self.shared),
raw: Arc::new(Mutex::new(queue)),
},
})
}

View File

@@ -343,35 +343,16 @@ impl crate::Device<super::Api> for super::Device {
}
unsafe fn destroy_sampler(&self, _sampler: super::Sampler) {}
unsafe fn create_command_buffer(
unsafe fn create_command_pool(
&self,
desc: &crate::CommandBufferDescriptor,
) -> DeviceResult<super::CommandBuffer> {
let raw = self.shared.create_command_buffer();
if let Some(label) = desc.label {
raw.set_label(label);
}
Ok(super::CommandBuffer {
raw,
blit: None,
render: None,
compute: None,
disabilities: self.shared.disabilities.clone(),
max_buffers_per_stage: self.shared.private_caps.max_buffers_per_stage,
state: super::CommandState {
raw_primitive_type: mtl::MTLPrimitiveType::Point,
index: None,
raw_wg_size: mtl::MTLSize::new(0, 0, 0),
stage_infos: Default::default(),
storage_buffer_length_map: Default::default(),
},
temp: super::Temp::default(),
desc: &crate::CommandPoolDescriptor<super::Api>,
) -> Result<super::CommandPool, crate::DeviceError> {
Ok(super::CommandPool {
shared: Arc::clone(&self.shared),
raw_queue: Arc::clone(&desc.queue.raw),
})
}
unsafe fn destroy_command_buffer(&self, mut cmd_buf: super::CommandBuffer) {
cmd_buf.leave_blit();
}
unsafe fn destroy_command_pool(&self, _pool: super::CommandPool) {}
unsafe fn create_bind_group_layout(
&self,

View File

@@ -24,9 +24,10 @@ impl crate::Api for Api {
type Instance = Instance;
type Surface = Surface;
type Adapter = Adapter;
type Queue = Queue;
type Device = Device;
type Queue = Queue;
type CommandPool = CommandPool;
type CommandBuffer = CommandBuffer;
type Buffer = Buffer;
@@ -208,7 +209,6 @@ struct Settings {
struct AdapterShared {
device: Mutex<mtl::Device>,
queue: Mutex<mtl::CommandQueue>,
disabilities: PrivateDisabilities,
private_caps: PrivateCapabilities,
settings: Settings,
@@ -225,23 +225,10 @@ impl AdapterShared {
Self {
disabilities: PrivateDisabilities::new(&device),
private_caps: PrivateCapabilities::new(&device),
queue: Mutex::new(device.new_command_queue()),
device: Mutex::new(device),
settings: Settings::default(),
}
}
fn create_command_buffer(&self) -> mtl::CommandBuffer {
let queue = self.queue.lock();
objc::rc::autoreleasepool(move || {
let cmd_buf_ref = if self.settings.retain_command_buffer_references {
queue.new_command_buffer()
} else {
queue.new_command_buffer_with_unretained_references()
};
cmd_buf_ref.to_owned()
})
}
}
pub struct Adapter {
@@ -249,9 +236,12 @@ pub struct Adapter {
}
pub struct Queue {
shared: Arc<AdapterShared>,
raw: Arc<Mutex<mtl::CommandQueue>>,
}
unsafe impl Send for Queue {}
unsafe impl Sync for Queue {}
pub struct Device {
shared: Arc<AdapterShared>,
features: wgt::Features,
@@ -287,35 +277,49 @@ unsafe impl Send for SurfaceTexture {}
unsafe impl Sync for SurfaceTexture {}
impl crate::Queue<Api> for Queue {
unsafe fn submit<I>(
unsafe fn submit(
&mut self,
command_buffers: I,
command_buffers: &[&CommandBuffer],
signal_fence: Option<(&mut Fence, crate::FenceValue)>,
) -> Result<(), crate::DeviceError>
where
I: Iterator<Item = CommandBuffer>,
{
) -> Result<(), crate::DeviceError> {
objc::rc::autoreleasepool(|| {
let extra_command_buffer = match signal_fence {
Some((fence, value)) => {
let completed_value = Arc::clone(&fence.completed_value);
let block = block::ConcreteBlock::new(move |_cmd_buf| {
completed_value.store(value, atomic::Ordering::Release);
})
.copy();
let raw = match command_buffers.last() {
Some(&cmd_buf) => cmd_buf.raw.to_owned(),
None => {
let queue = self.raw.lock();
queue
.new_command_buffer_with_unretained_references()
.to_owned()
}
};
raw.set_label("_Signal");
raw.add_completed_handler(&block);
fence.update();
fence.pending_command_buffers.push((value, raw.to_owned()));
// only return an extra one if it's extra
match command_buffers.last() {
Some(_) => None,
None => Some(raw),
}
}
None => None,
};
for cmd_buffer in command_buffers {
cmd_buffer.raw.commit();
}
//TODO: add the handler to the last command buffer in the list
// instead of committing an extra one
if let Some((fence, value)) = signal_fence {
let completed_value = Arc::clone(&fence.completed_value);
let block = block::ConcreteBlock::new(move |_cmd_buf| {
completed_value.store(value, atomic::Ordering::Release);
})
.copy();
let raw = self.shared.create_command_buffer();
raw.set_label("_Signal");
raw.add_completed_handler(&block);
if let Some(raw) = extra_command_buffer {
raw.commit();
fence.update();
fence.pending_command_buffers.push((value, raw));
}
});
Ok(())
@@ -325,7 +329,7 @@ impl crate::Queue<Api> for Queue {
_surface: &mut Surface,
texture: SurfaceTexture,
) -> Result<(), crate::SurfaceError> {
let queue = self.shared.queue.lock();
let queue = &self.raw.lock();
objc::rc::autoreleasepool(|| {
let command_buffer = queue.new_command_buffer();
command_buffer.set_label("_Present");
@@ -346,6 +350,49 @@ impl crate::Queue<Api> for Queue {
}
}
impl crate::CommandPool<Api> for CommandPool {
unsafe fn allocate(
&mut self,
desc: &crate::CommandBufferDescriptor,
) -> Result<CommandBuffer, crate::DeviceError> {
let queue = &self.raw_queue.lock();
let retain_references = self.shared.settings.retain_command_buffer_references;
let raw = objc::rc::autoreleasepool(move || {
let cmd_buf_ref = if retain_references {
queue.new_command_buffer()
} else {
queue.new_command_buffer_with_unretained_references()
};
cmd_buf_ref.to_owned()
});
if let Some(label) = desc.label {
raw.set_label(label);
}
Ok(CommandBuffer {
raw,
blit: None,
render: None,
compute: None,
disabilities: self.shared.disabilities.clone(),
max_buffers_per_stage: self.shared.private_caps.max_buffers_per_stage,
state: CommandState {
raw_primitive_type: mtl::MTLPrimitiveType::Point,
index: None,
raw_wg_size: mtl::MTLSize::new(0, 0, 0),
stage_infos: Default::default(),
storage_buffer_length_map: Default::default(),
},
temp: Temp::default(),
})
}
unsafe fn free(&mut self, mut cmd_buf: CommandBuffer) {
cmd_buf.leave_blit();
}
unsafe fn clear(&mut self) {}
}
#[derive(Debug)]
pub struct Buffer {
raw: mtl::Buffer,
@@ -639,6 +686,14 @@ impl Fence {
}
}
pub struct CommandPool {
shared: Arc<AdapterShared>,
raw_queue: Arc<Mutex<mtl::CommandQueue>>,
}
unsafe impl Send for CommandPool {}
unsafe impl Sync for CommandPool {}
struct IndexState {
buffer_ptr: BufferPtr,
offset: wgt::BufferAddress,

View File

@@ -341,7 +341,7 @@ impl super::Device {
}
}
use super::{DeviceResult, Encoder, Resource}; //temporary
use super::{DeviceResult, Resource}; //temporary
impl crate::Device<super::Api> for super::Device {
unsafe fn create_buffer(
@@ -604,13 +604,13 @@ impl crate::Device<super::Api> for super::Device {
self.shared.raw.destroy_sampler(sampler.raw, None);
}
unsafe fn create_command_buffer(
unsafe fn create_command_pool(
&self,
desc: &crate::CommandBufferDescriptor,
) -> DeviceResult<Encoder> {
Ok(Encoder)
desc: &crate::CommandPoolDescriptor<super::Api>,
) -> DeviceResult<super::CommandPool> {
Ok(super::CommandPool {})
}
unsafe fn destroy_command_buffer(&self, cmd_buf: Encoder) {}
unsafe fn destroy_command_pool(&self, cmd_pool: super::CommandPool) {}
unsafe fn create_bind_group_layout(
&self,

View File

@@ -28,9 +28,10 @@ impl crate::Api for Api {
type Instance = Instance;
type Surface = Surface;
type Adapter = Adapter;
type Queue = Queue;
type Device = Device;
type Queue = Queue;
type CommandPool = CommandPool;
type CommandBuffer = Encoder;
type Buffer = Buffer;
@@ -198,10 +199,15 @@ pub struct BindGroup {
raw: gpu_descriptor::DescriptorSet<vk::DescriptorSet>,
}
#[derive(Debug)]
pub struct CommandPool {
//TODO
}
impl crate::Queue<Api> for Queue {
unsafe fn submit<I>(
unsafe fn submit(
&mut self,
command_buffers: I,
command_buffers: &[&Encoder],
signal_fence: Option<(&mut Resource, crate::FenceValue)>,
) -> DeviceResult<()> {
Ok(())
@@ -215,6 +221,14 @@ impl crate::Queue<Api> for Queue {
}
}
impl crate::CommandPool<Api> for CommandPool {
unsafe fn allocate(&mut self, desc: &crate::CommandBufferDescriptor) -> DeviceResult<Encoder> {
Ok(Encoder)
}
unsafe fn free(&mut self, cmd_buf: Encoder) {}
unsafe fn clear(&mut self) {}
}
impl From<vk::Result> for crate::DeviceError {
fn from(result: vk::Result) -> Self {
match result {