mirror of
https://github.com/vulkano-rs/vulkano.git
synced 2024-11-25 08:14:20 +00:00
Merge pull request #685 from tomaka/cache-ds
Cache descriptor sets in the state cacher
This commit is contained in:
commit
c0d4afb0fa
@ -751,7 +751,7 @@ impl<P> AutoCommandBufferBuilder<P> {
|
||||
}
|
||||
|
||||
push_constants(&mut self.inner, pipeline.clone(), constants);
|
||||
descriptor_sets(&mut self.inner, false, pipeline.clone(), sets)?;
|
||||
descriptor_sets(&mut self.inner, &mut self.state_cacher, false, pipeline.clone(), sets)?;
|
||||
|
||||
self.inner.dispatch(dimensions);
|
||||
Ok(self)
|
||||
@ -783,7 +783,7 @@ impl<P> AutoCommandBufferBuilder<P> {
|
||||
|
||||
push_constants(&mut self.inner, pipeline.clone(), constants);
|
||||
set_state(&mut self.inner, dynamic);
|
||||
descriptor_sets(&mut self.inner, true, pipeline.clone(), sets)?;
|
||||
descriptor_sets(&mut self.inner, &mut self.state_cacher, true, pipeline.clone(), sets)?;
|
||||
vertex_buffers(&mut self.inner, vb_infos.vertex_buffers)?;
|
||||
|
||||
debug_assert!(self.graphics_allowed);
|
||||
@ -830,7 +830,7 @@ impl<P> AutoCommandBufferBuilder<P> {
|
||||
|
||||
push_constants(&mut self.inner, pipeline.clone(), constants);
|
||||
set_state(&mut self.inner, dynamic);
|
||||
descriptor_sets(&mut self.inner, true, pipeline.clone(), sets)?;
|
||||
descriptor_sets(&mut self.inner, &mut self.state_cacher, true, pipeline.clone(), sets)?;
|
||||
vertex_buffers(&mut self.inner, vb_infos.vertex_buffers)?;
|
||||
// TODO: how to handle an index out of range of the vertex buffers?
|
||||
|
||||
@ -874,7 +874,7 @@ impl<P> AutoCommandBufferBuilder<P> {
|
||||
|
||||
push_constants(&mut self.inner, pipeline.clone(), constants);
|
||||
set_state(&mut self.inner, dynamic);
|
||||
descriptor_sets(&mut self.inner, true, pipeline.clone(), sets)?;
|
||||
descriptor_sets(&mut self.inner, &mut self.state_cacher, true, pipeline.clone(), sets)?;
|
||||
vertex_buffers(&mut self.inner, vb_infos.vertex_buffers)?;
|
||||
|
||||
debug_assert!(self.graphics_allowed);
|
||||
@ -1077,19 +1077,33 @@ unsafe fn vertex_buffers<P>(destination: &mut SyncCommandBufferBuilder<P>,
|
||||
Ok(())
|
||||
}
|
||||
|
||||
unsafe fn descriptor_sets<P, Pl, S>(destination: &mut SyncCommandBufferBuilder<P>, gfx: bool,
|
||||
pipeline: Pl, sets: S)
|
||||
unsafe fn descriptor_sets<P, Pl, S>(destination: &mut SyncCommandBufferBuilder<P>,
|
||||
state_cacher: &mut StateCacher,
|
||||
gfx: bool, pipeline: Pl, sets: S)
|
||||
-> Result<(), SyncCommandBufferBuilderError>
|
||||
where Pl: PipelineLayoutAbstract + Send + Sync + Clone + 'static,
|
||||
S: DescriptorSetsCollection
|
||||
{
|
||||
let mut sets_binder = destination.bind_descriptor_sets();
|
||||
let sets = sets.into_vec();
|
||||
|
||||
for set in sets.into_vec() {
|
||||
let first_binding = {
|
||||
let mut compare = state_cacher.bind_descriptor_sets(gfx);
|
||||
for set in sets.iter() {
|
||||
compare.add(set);
|
||||
}
|
||||
compare.compare()
|
||||
};
|
||||
|
||||
let first_binding = match first_binding {
|
||||
None => return Ok(()),
|
||||
Some(fb) => fb,
|
||||
};
|
||||
|
||||
let mut sets_binder = destination.bind_descriptor_sets();
|
||||
for set in sets.into_iter().skip(first_binding as usize) {
|
||||
sets_binder.add(set);
|
||||
}
|
||||
|
||||
sets_binder.submit(gfx, pipeline.clone(), 0, iter::empty())?;
|
||||
sets_binder.submit(gfx, pipeline.clone(), first_binding, iter::empty())?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -10,9 +10,11 @@
|
||||
use VulkanObject;
|
||||
use buffer::BufferAccess;
|
||||
use command_buffer::DynamicState;
|
||||
use descriptor::DescriptorSet;
|
||||
use pipeline::input_assembly::IndexType;
|
||||
use pipeline::ComputePipelineAbstract;
|
||||
use pipeline::GraphicsPipelineAbstract;
|
||||
use smallvec::SmallVec;
|
||||
use vk;
|
||||
|
||||
/// Keep track of the state of a command buffer builder, so that you don't need to bind objects
|
||||
@ -27,6 +29,15 @@ pub struct StateCacher {
|
||||
compute_pipeline: vk::Pipeline,
|
||||
// The graphics pipeline currently bound. 0 if nothing bound.
|
||||
graphics_pipeline: vk::Pipeline,
|
||||
// The descriptor sets for the compute pipeline.
|
||||
compute_descriptor_sets: SmallVec<[vk::DescriptorSet; 12]>,
|
||||
// The descriptor sets for the graphics pipeline.
|
||||
graphics_descriptor_sets: SmallVec<[vk::DescriptorSet; 12]>,
|
||||
// If the user starts comparing descriptor sets, but drops the helper struct in the middle of
|
||||
// the processing then we will end up in a weird state. This bool is true when we start
|
||||
// comparing sets, and is set to false when we end up comparing. If it was true when we start
|
||||
// comparing, we know that something bad happened and we flush the cache.
|
||||
poisonned_descriptor_sets: bool,
|
||||
// The index buffer, offset, and index type currently bound. `None` if nothing bound.
|
||||
index_buffer: Option<(vk::Buffer, usize, IndexType)>,
|
||||
}
|
||||
@ -48,6 +59,9 @@ impl StateCacher {
|
||||
dynamic_state: DynamicState::none(),
|
||||
compute_pipeline: 0,
|
||||
graphics_pipeline: 0,
|
||||
compute_descriptor_sets: SmallVec::new(),
|
||||
graphics_descriptor_sets: SmallVec::new(),
|
||||
poisonned_descriptor_sets: false,
|
||||
index_buffer: None,
|
||||
}
|
||||
}
|
||||
@ -59,6 +73,8 @@ impl StateCacher {
|
||||
self.dynamic_state = DynamicState::none();
|
||||
self.compute_pipeline = 0;
|
||||
self.graphics_pipeline = 0;
|
||||
self.compute_descriptor_sets = SmallVec::new();
|
||||
self.graphics_descriptor_sets = SmallVec::new();
|
||||
self.index_buffer = None;
|
||||
}
|
||||
|
||||
@ -85,6 +101,36 @@ impl StateCacher {
|
||||
incoming
|
||||
}
|
||||
|
||||
/// Starts the process of comparing a list of descriptor sets to the descriptor sets currently
|
||||
/// in cache.
|
||||
///
|
||||
/// After calling this function, call `add` for each set one by one. Then call `compare` in
|
||||
/// order to get the index of the first set to bind, or `None` if the sets were identical to
|
||||
/// what is in cache.
|
||||
///
|
||||
/// This process also updates the state cacher. The state cacher assumes that the state
|
||||
/// changes are going to be performed after the `compare` function returns.
|
||||
#[inline]
|
||||
pub fn bind_descriptor_sets(&mut self, graphics: bool) -> StateCacherDescriptorSets {
|
||||
if self.poisonned_descriptor_sets {
|
||||
self.compute_descriptor_sets = SmallVec::new();
|
||||
self.graphics_descriptor_sets = SmallVec::new();
|
||||
}
|
||||
|
||||
self.poisonned_descriptor_sets = true;
|
||||
|
||||
StateCacherDescriptorSets {
|
||||
poisonned: &mut self.poisonned_descriptor_sets,
|
||||
state: if graphics {
|
||||
&mut self.graphics_descriptor_sets
|
||||
} else {
|
||||
&mut self.compute_descriptor_sets
|
||||
},
|
||||
offset: 0,
|
||||
found_diff: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks whether we need to bind a graphics pipeline. Returns `StateCacherOutcome::AlreadyOk`
|
||||
/// if the pipeline was already bound earlier, and `StateCacherOutcome::NeedChange` if you need
|
||||
/// to actually bind the pipeline.
|
||||
@ -144,69 +190,61 @@ impl StateCacher {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
unsafe impl<I, O> AddCommand<commands_raw::CmdSetState> for StateCacher<I>
|
||||
where I: AddCommand<commands_raw::CmdSetState, Out = O>
|
||||
{
|
||||
type Out = StateCacher<O>;
|
||||
/// Helper struct for comparing descriptor sets.
|
||||
///
|
||||
/// > **Note**: For safety reasons, if you drop/leak this struct before calling `compare` then the
|
||||
/// > cache of the currently bound descriptor sets will be reset.
|
||||
pub struct StateCacherDescriptorSets<'s> {
|
||||
// Reference to the parent's `poisonned_descriptor_sets`.
|
||||
poisonned: &'s mut bool,
|
||||
// Reference to the descriptor sets list to compare to.
|
||||
state: &'s mut SmallVec<[vk::DescriptorSet; 12]>,
|
||||
// Next offset within the list to compare to.
|
||||
offset: usize,
|
||||
// Contains the return value of `compare`.
|
||||
found_diff: Option<u32>,
|
||||
}
|
||||
|
||||
impl<'s> StateCacherDescriptorSets<'s> {
|
||||
/// Adds a descriptor set to the list to compare.
|
||||
#[inline]
|
||||
fn add(mut self, command: commands_raw::CmdSetState) -> Result<Self::Out, CommandAddError> {
|
||||
// We need to synchronize `self.dynamic_state` with the state in `command`.
|
||||
// While doing so, we tweak `command` to erase the states that are the same as what's
|
||||
// already in `self.dynamic_state`.
|
||||
pub fn add<S>(&mut self, set: &S)
|
||||
where S: ?Sized + DescriptorSet
|
||||
{
|
||||
let raw = set.inner().internal_object();
|
||||
|
||||
let mut command_state = command.state().clone();
|
||||
if self.offset < self.state.len() {
|
||||
if self.state[self.offset] == raw {
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle line width.
|
||||
if let Some(new_val) = command_state.line_width {
|
||||
if self.dynamic_state.line_width == Some(new_val) {
|
||||
command_state.line_width = None;
|
||||
} else {
|
||||
self.dynamic_state.line_width = Some(new_val);
|
||||
self.state[self.offset] = raw;
|
||||
|
||||
} else {
|
||||
self.state.push(raw);
|
||||
}
|
||||
|
||||
if self.found_diff.is_none() {
|
||||
self.found_diff = Some(self.offset as u32);
|
||||
}
|
||||
}
|
||||
|
||||
/// Compares your list to the list in cache, and returns the offset of the first set to bind.
|
||||
/// Returns `None` if the two lists were identical.
|
||||
///
|
||||
/// After this function returns, the cache will be updated to match your list.
|
||||
#[inline]
|
||||
pub fn compare(self) -> Option<u32> {
|
||||
*self.poisonned = false;
|
||||
|
||||
// Removing from the cache any set that wasn't added with `add`.
|
||||
if self.offset < self.state.len() {
|
||||
// TODO: SmallVec doesn't provide any method for this
|
||||
for _ in self.offset .. self.state.len() {
|
||||
self.state.remove(self.offset);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: missing implementations
|
||||
|
||||
Ok(StateCacher {
|
||||
inner: self.inner.add(commands_raw::CmdSetState::new(command.device().clone(), command_state))?,
|
||||
dynamic_state: self.dynamic_state,
|
||||
graphics_pipeline: self.graphics_pipeline,
|
||||
compute_pipeline: self.compute_pipeline,
|
||||
vertex_buffers: self.vertex_buffers,
|
||||
})
|
||||
self.found_diff
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<I, O, B> AddCommand<commands_raw::CmdBindVertexBuffers<B>> for StateCacher<I>
|
||||
where I: AddCommand<commands_raw::CmdBindVertexBuffers<B>, Out = O>
|
||||
{
|
||||
type Out = StateCacher<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(StateCacher {
|
||||
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,
|
||||
})
|
||||
}
|
||||
}*/
|
||||
|
@ -2271,6 +2271,10 @@ impl<'b, P> SyncCommandBufferBuilderBindDescriptorSets<'b, P> {
|
||||
where Pl: PipelineLayoutAbstract + Send + Sync + 'static,
|
||||
I: Iterator<Item = u32> + Send + Sync + 'static
|
||||
{
|
||||
if self.inner.is_empty() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
struct Cmd<Pl, I> {
|
||||
inner: SmallVec<[Box<DescriptorSet + Send + Sync>; 12]>,
|
||||
graphics: bool,
|
||||
|
Loading…
Reference in New Issue
Block a user