mirror of
https://github.com/vulkano-rs/vulkano.git
synced 2024-11-27 01:05:03 +00:00
Merge pull request #449 from tomaka/state-cache-vbs
Cache the current vertex buffers in StateCacheLayer
This commit is contained in:
commit
b81d204df9
@ -45,6 +45,8 @@ pub struct StateCacheLayer<I> {
|
||||
compute_pipeline: vk::Pipeline,
|
||||
// The graphics pipeline currently bound. 0 if nothing bound.
|
||||
graphics_pipeline: vk::Pipeline,
|
||||
// The latest bind vertex buffers command.
|
||||
vertex_buffers: Option<commands_raw::CmdBindVertexBuffersHash>,
|
||||
}
|
||||
|
||||
impl<I> StateCacheLayer<I> {
|
||||
@ -58,6 +60,7 @@ impl<I> StateCacheLayer<I> {
|
||||
dynamic_state: DynamicState::none(),
|
||||
compute_pipeline: 0,
|
||||
graphics_pipeline: 0,
|
||||
vertex_buffers: None,
|
||||
}
|
||||
}
|
||||
|
||||
@ -118,6 +121,7 @@ unsafe impl<Pl, I, O> AddCommand<commands_raw::CmdBindPipeline<Pl>> for StateCac
|
||||
dynamic_state: DynamicState::none(),
|
||||
graphics_pipeline: self.graphics_pipeline,
|
||||
compute_pipeline: self.compute_pipeline,
|
||||
vertex_buffers: self.vertex_buffers,
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -137,6 +141,7 @@ unsafe impl<Cb, I, O> AddCommand<commands_raw::CmdExecuteCommands<Cb>> for State
|
||||
dynamic_state: DynamicState::none(),
|
||||
compute_pipeline: 0,
|
||||
graphics_pipeline: 0,
|
||||
vertex_buffers: None,
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -170,6 +175,39 @@ unsafe impl<I, O> AddCommand<commands_raw::CmdSetState> for StateCacheLayer<I>
|
||||
dynamic_state: self.dynamic_state,
|
||||
graphics_pipeline: self.graphics_pipeline,
|
||||
compute_pipeline: self.compute_pipeline,
|
||||
vertex_buffers: self.vertex_buffers,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<I, O, B> AddCommand<commands_raw::CmdBindVertexBuffers<B>> for StateCacheLayer<I>
|
||||
where I: AddCommand<commands_raw::CmdBindVertexBuffers<B>, Out = O>
|
||||
{
|
||||
type Out = StateCacheLayer<O>;
|
||||
|
||||
#[inline]
|
||||
fn add(mut self, mut command: commands_raw::CmdBindVertexBuffers<B>)
|
||||
-> Result<Self::Out, CommandAddError>
|
||||
{
|
||||
match &mut self.vertex_buffers {
|
||||
&mut Some(ref mut curr) => {
|
||||
if *curr != *command.hash() {
|
||||
let new_hash = command.hash().clone();
|
||||
command.diff(curr);
|
||||
*curr = new_hash;
|
||||
}
|
||||
},
|
||||
curr @ &mut None => {
|
||||
*curr = Some(command.hash().clone());
|
||||
}
|
||||
};
|
||||
|
||||
Ok(StateCacheLayer {
|
||||
inner: self.inner.add(command)?,
|
||||
dynamic_state: self.dynamic_state,
|
||||
graphics_pipeline: self.graphics_pipeline,
|
||||
compute_pipeline: self.compute_pipeline,
|
||||
vertex_buffers: self.vertex_buffers,
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -200,6 +238,7 @@ macro_rules! pass_through {
|
||||
dynamic_state: self.dynamic_state,
|
||||
graphics_pipeline: self.graphics_pipeline,
|
||||
compute_pipeline: self.compute_pipeline,
|
||||
vertex_buffers: self.vertex_buffers,
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -209,7 +248,6 @@ macro_rules! pass_through {
|
||||
pass_through!((Rp, F), commands_raw::CmdBeginRenderPass<Rp, F>);
|
||||
pass_through!((S, Pl), commands_raw::CmdBindDescriptorSets<S, Pl>);
|
||||
pass_through!((B), commands_raw::CmdBindIndexBuffer<B>);
|
||||
pass_through!((V), commands_raw::CmdBindVertexBuffers<V>);
|
||||
pass_through!((S, D), commands_raw::CmdBlitImage<S, D>);
|
||||
pass_through!((), commands_raw::CmdClearAttachments);
|
||||
pass_through!((S, D), commands_raw::CmdCopyBuffer<S, D>);
|
||||
|
@ -23,16 +23,31 @@ use vk;
|
||||
|
||||
/// Command that binds vertex buffers to a command buffer.
|
||||
pub struct CmdBindVertexBuffers<B> {
|
||||
// Raw handles of the buffers to bind.
|
||||
raw_buffers: SmallVec<[vk::Buffer; 4]>,
|
||||
// Raw offsets of the buffers to bind.
|
||||
offsets: SmallVec<[vk::DeviceSize; 4]>,
|
||||
// Actual raw state of the command.
|
||||
state: CmdBindVertexBuffersHash,
|
||||
// Offset within `state` to start binding.
|
||||
first_binding: u32,
|
||||
// Number of bindings to pass to the command.
|
||||
num_bindings: u32,
|
||||
// The device of the buffer, so that we can compare it with the command buffer's device.
|
||||
device: Arc<Device>,
|
||||
// The buffers to bind. Unused, but we need to keep it alive.
|
||||
buffers: B,
|
||||
}
|
||||
|
||||
/// A "hash" of the bind vertex buffers command. Can be compared with a previous hash to determine
|
||||
/// if two commands are identical.
|
||||
///
|
||||
/// > **Note**: This is not *actually* a hash, because there's no collision. If two objects are
|
||||
/// > equal, then the commands are always identical.
|
||||
#[derive(Clone, PartialEq, Eq)]
|
||||
pub struct CmdBindVertexBuffersHash {
|
||||
// Raw handles of the buffers to bind.
|
||||
raw_buffers: SmallVec<[vk::Buffer; 4]>,
|
||||
// Raw offsets of the buffers to bind.
|
||||
offsets: SmallVec<[vk::DeviceSize; 4]>,
|
||||
}
|
||||
|
||||
impl<B> CmdBindVertexBuffers<B> {
|
||||
/// Builds the command.
|
||||
#[inline]
|
||||
@ -43,19 +58,65 @@ impl<B> CmdBindVertexBuffers<B> {
|
||||
let (buffers, _, _) = source_def.decode(&buffers);
|
||||
|
||||
let device = buffers.first().unwrap().buffer.device().clone();
|
||||
let raw_buffers = buffers.iter().map(|b| b.buffer.internal_object()).collect();
|
||||
let raw_buffers: SmallVec<_> = buffers.iter().map(|b| b.buffer.internal_object()).collect();
|
||||
let offsets = buffers.iter().map(|b| b.offset as vk::DeviceSize).collect();
|
||||
|
||||
(device, raw_buffers, offsets)
|
||||
};
|
||||
|
||||
let num_bindings = raw_buffers.len() as u32;
|
||||
|
||||
CmdBindVertexBuffers {
|
||||
raw_buffers: raw_buffers,
|
||||
offsets: offsets,
|
||||
state: CmdBindVertexBuffersHash {
|
||||
raw_buffers: raw_buffers,
|
||||
offsets: offsets,
|
||||
},
|
||||
first_binding: 0,
|
||||
num_bindings: num_bindings,
|
||||
device: device,
|
||||
buffers: buffers,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a hash that represents the command.
|
||||
#[inline]
|
||||
pub fn hash(&self) -> &CmdBindVertexBuffersHash {
|
||||
&self.state
|
||||
}
|
||||
|
||||
/// Modifies the command so that it doesn't bind vertex buffers that were already bound by a
|
||||
/// previous command with the given hash.
|
||||
///
|
||||
/// Note that this doesn't modify the hash of the command.
|
||||
pub fn diff(&mut self, previous_hash: &CmdBindVertexBuffersHash) {
|
||||
// We don't want to split the command into multiple ones, so we just trim the list of
|
||||
// vertex buffers at the start and at the end.
|
||||
let left_trim = self.state.raw_buffers
|
||||
.iter()
|
||||
.zip(self.state.offsets.iter())
|
||||
.zip(previous_hash.raw_buffers.iter())
|
||||
.zip(previous_hash.offsets.iter())
|
||||
.position(|(((&cur_buf, &cur_off), &prev_buf), &prev_off)| {
|
||||
cur_buf != prev_buf || cur_off != prev_off
|
||||
})
|
||||
.map(|p| p as u32)
|
||||
.unwrap_or(self.num_bindings);
|
||||
|
||||
let right_trim = self.state.raw_buffers
|
||||
.iter()
|
||||
.zip(self.state.offsets.iter().rev())
|
||||
.zip(previous_hash.raw_buffers.iter().rev())
|
||||
.zip(previous_hash.offsets.iter().rev())
|
||||
.position(|(((&cur_buf, &cur_off), &prev_buf), &prev_off)| {
|
||||
cur_buf != prev_buf || cur_off != prev_off
|
||||
})
|
||||
.map(|p| p as u32)
|
||||
.unwrap_or(self.num_bindings);
|
||||
|
||||
self.first_binding = left_trim;
|
||||
debug_assert!(left_trim <= self.state.raw_buffers.len() as u32);
|
||||
self.num_bindings = (self.state.raw_buffers.len() as u32 - left_trim).saturating_sub(right_trim);
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<B> DeviceOwned for CmdBindVertexBuffers<B> {
|
||||
@ -73,10 +134,19 @@ unsafe impl<'a, P, B> AddCommand<&'a CmdBindVertexBuffers<B>> for UnsafeCommandB
|
||||
#[inline]
|
||||
fn add(self, command: &'a CmdBindVertexBuffers<B>) -> Result<Self::Out, CommandAddError> {
|
||||
unsafe {
|
||||
debug_assert_eq!(command.state.offsets.len(), command.state.raw_buffers.len());
|
||||
debug_assert!(command.num_bindings <= command.state.raw_buffers.len() as u32);
|
||||
|
||||
if command.num_bindings == 0 {
|
||||
return Ok(self);
|
||||
}
|
||||
|
||||
let vk = self.device().pointers();
|
||||
let cmd = self.internal_object();
|
||||
vk.CmdBindVertexBuffers(cmd, 0, command.raw_buffers.len() as u32,
|
||||
command.raw_buffers.as_ptr(), command.offsets.as_ptr());
|
||||
vk.CmdBindVertexBuffers(cmd, command.first_binding,
|
||||
command.num_bindings,
|
||||
command.state.raw_buffers[command.first_binding as usize..].as_ptr(),
|
||||
command.state.offsets[command.first_binding as usize..].as_ptr());
|
||||
}
|
||||
|
||||
Ok(self)
|
||||
|
@ -15,7 +15,7 @@ pub use self::begin_render_pass::CmdBeginRenderPass;
|
||||
pub use self::bind_index_buffer::CmdBindIndexBuffer;
|
||||
pub use self::bind_descriptor_sets::{CmdBindDescriptorSets, CmdBindDescriptorSetsError};
|
||||
pub use self::bind_pipeline::{CmdBindPipeline, CmdBindPipelineSys};
|
||||
pub use self::bind_vertex_buffers::CmdBindVertexBuffers;
|
||||
pub use self::bind_vertex_buffers::{CmdBindVertexBuffers, CmdBindVertexBuffersHash};
|
||||
pub use self::blit_image::{CmdBlitImage, CmdBlitImageError};
|
||||
pub use self::clear_attachments::CmdClearAttachments;
|
||||
pub use self::copy_buffer::{CmdCopyBuffer, CmdCopyBufferError};
|
||||
|
Loading…
Reference in New Issue
Block a user