Transition between command buffers

This commit is contained in:
Dzmitry Malyshau 2018-10-26 22:15:48 -04:00
parent 879cd64b30
commit f3cfd2e09c
8 changed files with 96 additions and 63 deletions

1
Cargo.lock generated
View File

@ -1047,6 +1047,7 @@ dependencies = [
"gfx-backend-vulkan 0.1.0 (git+https://github.com/gfx-rs/gfx)",
"gfx-hal 0.1.0 (git+https://github.com/gfx-rs/gfx.git)",
"lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
"parking_lot 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)",
"rendy-memory 0.1.0 (git+https://github.com/rustgd/rendy?rev=ce7dd7f)",
]

View File

@ -16,6 +16,7 @@ remote = ["parking_lot"]
[dependencies]
bitflags = "1.0"
lazy_static = "1.1.0"
log = "0.4"
parking_lot = { version = "0.6", optional = true }
gfx-hal = { git = "https://github.com/gfx-rs/gfx" } # required by gfx-memory
gfx-backend-empty = { git = "https://github.com/gfx-rs/gfx" }

View File

@ -10,7 +10,7 @@ use hal::{self, Device};
use hal::command::RawCommandBuffer;
use {
Color, Origin3d, Stored,
B, Color, Origin3d, Stored, BufferUsageFlags, TextureUsageFlags,
BufferId, CommandBufferId, ComputePassId, DeviceId, RenderPassId, TextureId, TextureViewId,
};
use conv;
@ -18,6 +18,7 @@ use registry::{HUB, Items, Registry};
use track::{BufferTracker, TextureTracker};
use std::iter;
use std::ops::Range;
use std::thread::ThreadId;
@ -81,8 +82,49 @@ pub struct CommandBuffer<B: hal::Backend> {
fence: B::Fence,
recorded_thread_id: ThreadId,
device_id: Stored<DeviceId>,
buffer_tracker: BufferTracker,
texture_tracker: TextureTracker,
pub(crate) buffer_tracker: BufferTracker,
pub(crate) texture_tracker: TextureTracker,
}
impl CommandBuffer<B> {
pub(crate) fn insert_barriers<I, J>(
raw: &mut <B as hal::Backend>::CommandBuffer,
buffer_iter: I,
texture_iter: J,
) where
I: Iterator<Item = (BufferId, Range<BufferUsageFlags>)>,
J: Iterator<Item = (TextureId, Range<TextureUsageFlags>)>,
{
let buffer_guard = HUB.buffers.lock();
let texture_guard = HUB.textures.lock();
let buffer_barriers = buffer_iter.map(|(id, transit)| {
let b = buffer_guard.get(id);
trace!("transit {:?} {:?}", id, transit);
hal::memory::Barrier::Buffer {
states: conv::map_buffer_state(transit.start) ..
conv::map_buffer_state(transit.end),
target: &b.raw,
}
});
let texture_barriers = texture_iter.map(|(id, transit)| {
let t = texture_guard.get(id);
trace!("transit {:?} {:?}", id, transit);
let aspects = t.full_range.aspects;
hal::memory::Barrier::Image {
states: conv::map_texture_state(transit.start, aspects) ..
conv::map_texture_state(transit.end, aspects),
target: &t.raw,
range: t.full_range.clone(), //TODO?
}
});
raw.pipeline_barrier(
hal::pso::PipelineStage::TOP_OF_PIPE .. hal::pso::PipelineStage::BOTTOM_OF_PIPE,
hal::memory::Dependencies::empty(),
buffer_barriers.chain(texture_barriers),
);
}
}
#[repr(C)]
@ -117,7 +159,7 @@ pub extern "C" fn wgpu_command_buffer_begin_render_pass(
} else {
extent = Some(view.extent);
}
let query = tracker.query(view.texture_id.0);
let query = tracker.query(view.texture_id.0, TextureUsageFlags::empty());
let (_, layout) = conv::map_texture_state(
query.usage,
hal::format::Aspects::DEPTH | hal::format::Aspects::STENCIL,
@ -141,7 +183,7 @@ pub extern "C" fn wgpu_command_buffer_begin_render_pass(
} else {
extent = Some(view.extent);
}
let query = tracker.query(view.texture_id.0);
let query = tracker.query(view.texture_id.0, TextureUsageFlags::empty());
let (_, layout) = conv::map_texture_state(query.usage, hal::format::Aspects::COLOR);
hal::pass::Attachment {
format: Some(conv::map_texture_format(view.format)),

View File

@ -1,8 +1,7 @@
use conv;
use registry::{HUB, Items, Registry};
use track::{BufferTracker, TextureTracker};
use {
Stored,
CommandBuffer, Stored,
CommandBufferId, RenderPassId,
};
@ -44,36 +43,10 @@ pub extern "C" fn wgpu_render_pass_end_pass(
let cmb = cmb_guard.get_mut(pass.cmb_id.0);
if let Some(ref mut last) = cmb.raw.last_mut() {
let buffer_guard = HUB.buffers.lock();
let texture_guard = HUB.textures.lock();
let buffer_barriers = cmb.buffer_tracker
.consume(pass.buffer_tracker)
.map(|(id, transit)| {
let b = buffer_guard.get(id);
hal::memory::Barrier::Buffer {
states: conv::map_buffer_state(transit.start) ..
conv::map_buffer_state(transit.end),
target: &b.raw,
}
});
let texture_barriers = cmb.texture_tracker
.consume(pass.texture_tracker)
.map(|(id, transit)| {
let t = texture_guard.get(id);
let aspects = t.full_range.aspects;
hal::memory::Barrier::Image {
states: conv::map_texture_state(transit.start, aspects) ..
conv::map_texture_state(transit.end, aspects),
target: &t.raw,
range: t.full_range.clone(), //TODO?
}
});
last.pipeline_barrier(
hal::pso::PipelineStage::TOP_OF_PIPE .. hal::pso::PipelineStage::BOTTOM_OF_PIPE,
hal::memory::Dependencies::empty(),
buffer_barriers.chain(texture_barriers),
CommandBuffer::insert_barriers(
last,
cmb.buffer_tracker.consume(&pass.buffer_tracker),
cmb.texture_tracker.consume(&pass.texture_tracker),
);
last.finish();
}

View File

@ -364,6 +364,7 @@ pub fn map_texture_state(
let is_color = aspects.contains(hal::format::Aspects::COLOR);
let layout = match usage {
W::WRITE_ALL => return (A::empty(), L::Undefined), // special value
W::TRANSFER_SRC => L::TransferSrcOptimal,
W::TRANSFER_DST => L::TransferDstOptimal,
W::SAMPLED => L::ShaderReadOnlyOptimal,

View File

@ -2,7 +2,7 @@ use {back, binding_model, command, conv, pipeline, resource};
use registry::{HUB, Items, Registry};
use track::{BufferTracker, TextureTracker};
use {
Stored,
CommandBuffer, Stored, TextureUsageFlags,
AttachmentStateId, BindGroupLayoutId, BlendStateId, CommandBufferId, DepthStencilStateId,
DeviceId, PipelineLayoutId, QueueId, RenderPipelineId, ShaderModuleId,
TextureId, TextureViewId,
@ -130,7 +130,7 @@ pub extern "C" fn wgpu_device_create_texture(
let query = device.texture_tracker
.lock()
.unwrap()
.query(id);
.query(id, TextureUsageFlags::WRITE_ALL);
assert!(query.initialized);
id
@ -341,16 +341,34 @@ pub extern "C" fn wgpu_queue_submit(
) {
let mut device_guard = HUB.devices.lock();
let device = device_guard.get_mut(queue_id);
let mut buffer_tracker = device.buffer_tracker.lock().unwrap();
let mut texture_tracker = device.texture_tracker.lock().unwrap();
let mut command_buffer_guard = HUB.command_buffers.lock();
let command_buffer_ids = unsafe {
slice::from_raw_parts(command_buffer_ptr, command_buffer_count)
};
//TODO: if multiple command buffers are submitted, we can re-use the last
// native command buffer of the previous chain instead of always creating
// a temporary one, since the chains are not finished.
// finish all the command buffers first
for &cmb_id in command_buffer_ids {
command_buffer_guard
.get_mut(cmb_id)
.raw
let comb = command_buffer_guard.get_mut(cmb_id);
let mut transit = device.com_allocator.extend(comb);
transit.begin(
hal::command::CommandBufferFlags::ONE_TIME_SUBMIT,
hal::command::CommandBufferInheritanceInfo::default(),
);
CommandBuffer::insert_barriers(
&mut transit,
buffer_tracker.consume(&comb.buffer_tracker),
texture_tracker.consume(&comb.texture_tracker),
);
transit.finish();
comb.raw.insert(0, transit);
comb.raw
.last_mut()
.unwrap()
.finish();

View File

@ -2,6 +2,8 @@
extern crate bitflags;
#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate log;
#[cfg(feature = "remote")]
extern crate parking_lot;

View File

@ -29,29 +29,23 @@ bitflags! {
pub trait GenericUsage {
fn default() -> Self;
fn is_exclusive(&self) -> bool;
}
impl GenericUsage for BufferUsageFlags {
fn default() -> Self {
BufferUsageFlags::empty()
}
fn is_exclusive(&self) -> bool {
BufferUsageFlags::WRITE_ALL.intersects(*self)
}
}
impl GenericUsage for TextureUsageFlags {
fn default() -> Self {
TextureUsageFlags::empty()
}
fn is_exclusive(&self) -> bool {
TextureUsageFlags::WRITE_ALL.intersects(*self)
}
}
//TODO: consider having `I` as an associated type of `U`?
pub struct Tracker<I, U> {
map: HashMap<Stored<I>, U>,
map: HashMap<Stored<I>, Range<U>>,
}
pub type BufferTracker = Tracker<BufferId, BufferUsageFlags>;
pub type TextureTracker = Tracker<TextureId, TextureUsageFlags>;
@ -66,19 +60,18 @@ impl<
}
}
pub fn query(&mut self, id: I) -> Query<U> {
pub fn query(&mut self, id: I, default: U) -> Query<U> {
match self.map.entry(Stored(id)) {
Entry::Vacant(e) => {
let usage = U::default();
e.insert(usage);
e.insert(default .. default);
Query {
usage,
usage: default,
initialized: true,
}
}
Entry::Occupied(e) => {
Query {
usage: *e.get(),
usage: e.get().end,
initialized: false,
}
}
@ -88,17 +81,19 @@ impl<
pub fn transit(&mut self, id: I, usage: U, permit: TrackPermit) -> Result<Tracktion<U>, U> {
match self.map.entry(Stored(id)) {
Entry::Vacant(e) => {
e.insert(usage);
e.insert(usage .. usage);
Ok(Tracktion::Init)
}
Entry::Occupied(mut e) => {
let old = *e.get();
let old = e.get().end;
if usage == old {
Ok(Tracktion::Keep)
} else if permit.contains(TrackPermit::EXTEND) && !(old | usage).is_exclusive() {
Ok(Tracktion::Extend { old: e.insert(old | usage) })
e.get_mut().end = old | usage;
Ok(Tracktion::Extend { old })
} else if permit.contains(TrackPermit::REPLACE) {
Ok(Tracktion::Replace { old: e.insert(usage) })
e.get_mut().end = usage;
Ok(Tracktion::Replace { old })
} else {
Err(old)
}
@ -106,13 +101,13 @@ impl<
}
}
pub(crate) fn consume<'a>(&'a mut self, other: Self) -> impl 'a + Iterator<Item = (I, Range<U>)> {
pub fn consume<'a>(&'a mut self, other: &'a Self) -> impl 'a + Iterator<Item = (I, Range<U>)> {
other.map
.into_iter()
.flat_map(move |(id, new)| match self.transit(id.0.clone(), new, TrackPermit::REPLACE) {
.iter()
.flat_map(move |(id, new)| match self.transit(id.0.clone(), new.end, TrackPermit::REPLACE) {
Ok(Tracktion::Init) |
Ok(Tracktion::Keep) => None,
Ok(Tracktion::Replace { old }) => Some((id.0, old .. new)),
Ok(Tracktion::Replace { old }) => Some((id.0.clone(), old .. new.end)),
Ok(Tracktion::Extend { .. }) |
Err(_) => panic!("Unable to consume a resource transition!"),
})