use crate::{
buffer::{BufferAccess, BufferContents, TypedBufferAccess},
command_buffer::{
allocator::CommandBufferAllocator,
auto::RenderPassStateType,
synced::{Command, SetOrPush, SyncCommandBufferBuilder},
sys::UnsafeCommandBufferBuilder,
AutoCommandBufferBuilder,
},
descriptor_set::{
check_descriptor_write, sys::UnsafeDescriptorSet, DescriptorSetResources,
DescriptorSetUpdateError, DescriptorSetWithOffsets, DescriptorSetsCollection,
DescriptorWriteInfo, WriteDescriptorSet,
},
device::DeviceOwned,
pipeline::{
graphics::{
input_assembly::{Index, IndexType},
render_pass::PipelineRenderPassType,
vertex_input::VertexBuffersCollection,
},
ComputePipeline, GraphicsPipeline, PipelineBindPoint, PipelineLayout,
},
shader::ShaderStages,
DeviceSize, RequirementNotMet, RequiresOneOf, VulkanObject,
};
use parking_lot::Mutex;
use smallvec::SmallVec;
use std::{
error,
fmt::{Display, Error as FmtError, Formatter},
mem::{size_of, size_of_val},
ptr, slice,
sync::Arc,
};
impl<L, A> AutoCommandBufferBuilder<L, A>
where
A: CommandBufferAllocator,
{
pub fn bind_descriptor_sets<S>(
&mut self,
pipeline_bind_point: PipelineBindPoint,
pipeline_layout: Arc<PipelineLayout>,
first_set: u32,
descriptor_sets: S,
) -> &mut Self
where
S: DescriptorSetsCollection,
{
let descriptor_sets = descriptor_sets.into_vec();
self.validate_bind_descriptor_sets(
pipeline_bind_point,
&pipeline_layout,
first_set,
&descriptor_sets,
)
.unwrap();
unsafe {
let mut sets_binder = self.inner.bind_descriptor_sets();
for set in descriptor_sets.into_iter() {
sets_binder.add(set);
}
sets_binder.submit(pipeline_bind_point, pipeline_layout, first_set);
}
self
}
fn validate_bind_descriptor_sets(
&self,
pipeline_bind_point: PipelineBindPoint,
pipeline_layout: &PipelineLayout,
first_set: u32,
descriptor_sets: &[DescriptorSetWithOffsets],
) -> Result<(), BindPushError> {
pipeline_bind_point.validate_device(self.device())?;
let queue_family_properties = self.queue_family_properties();
match pipeline_bind_point {
PipelineBindPoint::Compute => {
if !queue_family_properties.queue_flags.compute {
return Err(BindPushError::NotSupportedByQueueFamily);
}
}
PipelineBindPoint::Graphics => {
if !queue_family_properties.queue_flags.graphics {
return Err(BindPushError::NotSupportedByQueueFamily);
}
}
}
if first_set + descriptor_sets.len() as u32 > pipeline_layout.set_layouts().len() as u32 {
return Err(BindPushError::DescriptorSetOutOfRange {
set_num: first_set + descriptor_sets.len() as u32,
pipeline_layout_set_count: pipeline_layout.set_layouts().len() as u32,
});
}
for (i, set) in descriptor_sets.iter().enumerate() {
let set_num = first_set + i as u32;
assert_eq!(self.device(), set.as_ref().0.device());
let pipeline_layout_set = &pipeline_layout.set_layouts()[set_num as usize];
if !pipeline_layout_set.is_compatible_with(set.as_ref().0.layout()) {
return Err(BindPushError::DescriptorSetNotCompatible { set_num });
}
}
Ok(())
}
pub fn bind_index_buffer<Ib, I>(&mut self, index_buffer: Arc<Ib>) -> &mut Self
where
Ib: TypedBufferAccess<Content = [I]> + 'static,
I: Index + 'static,
{
self.validate_bind_index_buffer(&index_buffer, I::ty())
.unwrap();
unsafe {
self.inner.bind_index_buffer(index_buffer, I::ty());
}
self
}
fn validate_bind_index_buffer(
&self,
index_buffer: &dyn BufferAccess,
index_type: IndexType,
) -> Result<(), BindPushError> {
let queue_family_properties = self.queue_family_properties();
if !queue_family_properties.queue_flags.graphics {
return Err(BindPushError::NotSupportedByQueueFamily);
}
assert_eq!(self.device(), index_buffer.device());
if !index_buffer.usage().index_buffer {
return Err(BindPushError::IndexBufferMissingUsage);
}
if index_type == IndexType::U8 && !self.device().enabled_features().index_type_uint8 {
return Err(BindPushError::RequirementNotMet {
required_for: "`index_type` is `IndexType::U8`",
requires_one_of: RequiresOneOf {
features: &["index_type_uint8"],
..Default::default()
},
});
}
Ok(())
}
pub fn bind_pipeline_compute(&mut self, pipeline: Arc<ComputePipeline>) -> &mut Self {
self.validate_bind_pipeline_compute(&pipeline).unwrap();
unsafe {
self.inner.bind_pipeline_compute(pipeline);
}
self
}
fn validate_bind_pipeline_compute(
&self,
pipeline: &ComputePipeline,
) -> Result<(), BindPushError> {
let queue_family_properties = self.queue_family_properties();
if !queue_family_properties.queue_flags.compute {
return Err(BindPushError::NotSupportedByQueueFamily);
}
assert_eq!(self.device(), pipeline.device());
Ok(())
}
pub fn bind_pipeline_graphics(&mut self, pipeline: Arc<GraphicsPipeline>) -> &mut Self {
self.validate_bind_pipeline_graphics(&pipeline).unwrap();
unsafe {
self.inner.bind_pipeline_graphics(pipeline);
}
self
}
fn validate_bind_pipeline_graphics(
&self,
pipeline: &GraphicsPipeline,
) -> Result<(), BindPushError> {
let queue_family_properties = self.queue_family_properties();
if !queue_family_properties.queue_flags.graphics {
return Err(BindPushError::NotSupportedByQueueFamily);
}
assert_eq!(self.device(), pipeline.device());
if let Some(last_pipeline) = self
.render_pass_state
.as_ref()
.and_then(|render_pass_state| match &render_pass_state.render_pass {
RenderPassStateType::BeginRendering(state) if state.pipeline_used => {
self.state().pipeline_graphics()
}
_ => None,
})
{
if let (
PipelineRenderPassType::BeginRendering(pipeline_rendering_info),
PipelineRenderPassType::BeginRendering(last_pipeline_rendering_info),
) = (pipeline.render_pass(), last_pipeline.render_pass())
{
if pipeline_rendering_info.color_attachment_formats
!= last_pipeline_rendering_info.color_attachment_formats
{
return Err(BindPushError::PreviousPipelineColorAttachmentFormatMismatch);
}
if pipeline_rendering_info.depth_attachment_format
!= last_pipeline_rendering_info.depth_attachment_format
{
return Err(BindPushError::PreviousPipelineDepthAttachmentFormatMismatch);
}
if pipeline_rendering_info.stencil_attachment_format
!= last_pipeline_rendering_info.stencil_attachment_format
{
return Err(BindPushError::PreviousPipelineStencilAttachmentFormatMismatch);
}
}
}
Ok(())
}
pub fn bind_vertex_buffers(
&mut self,
first_binding: u32,
vertex_buffers: impl VertexBuffersCollection,
) -> &mut Self {
let vertex_buffers = vertex_buffers.into_vec();
self.validate_bind_vertex_buffers(first_binding, &vertex_buffers)
.unwrap();
unsafe {
let mut binder = self.inner.bind_vertex_buffers();
for vb in vertex_buffers.into_iter() {
binder.add(vb);
}
binder.submit(first_binding);
}
self
}
fn validate_bind_vertex_buffers(
&self,
first_binding: u32,
vertex_buffers: &[Arc<dyn BufferAccess>],
) -> Result<(), BindPushError> {
let queue_family_properties = self.queue_family_properties();
if !queue_family_properties.queue_flags.graphics {
return Err(BindPushError::NotSupportedByQueueFamily);
}
if first_binding + vertex_buffers.len() as u32
> self
.device()
.physical_device()
.properties()
.max_vertex_input_bindings
{
return Err(BindPushError::MaxVertexInputBindingsExceeded {
_binding_count: first_binding + vertex_buffers.len() as u32,
_max: self
.device()
.physical_device()
.properties()
.max_vertex_input_bindings,
});
}
for buffer in vertex_buffers {
assert_eq!(self.device(), buffer.device());
if !buffer.usage().vertex_buffer {
return Err(BindPushError::VertexBufferMissingUsage);
}
}
Ok(())
}
pub fn push_constants<Pc>(
&mut self,
pipeline_layout: Arc<PipelineLayout>,
offset: u32,
push_constants: Pc,
) -> &mut Self
where
Pc: BufferContents,
{
let size = size_of::<Pc>() as u32;
if size == 0 {
return self;
}
let push_constants = unsafe {
slice::from_raw_parts(&push_constants as *const Pc as *const u8, size as usize)
};
self.validate_push_constants(&pipeline_layout, offset, push_constants)
.unwrap();
let mut current_offset = offset;
let mut remaining_size = size;
for range in pipeline_layout
.push_constant_ranges_disjoint()
.iter()
.skip_while(|range| range.offset + range.size <= offset)
{
if range.offset > current_offset {
break;
}
let push_size = remaining_size.min(range.offset + range.size - current_offset);
let data_offset = (current_offset - offset) as usize;
unsafe {
self.inner.push_constants::<[u8]>(
pipeline_layout.clone(),
range.stages,
current_offset,
push_size,
&push_constants[data_offset..(data_offset + push_size as usize)],
);
}
current_offset += push_size;
remaining_size -= push_size;
if remaining_size == 0 {
break;
}
}
debug_assert!(remaining_size == 0);
self
}
fn validate_push_constants(
&self,
pipeline_layout: &PipelineLayout,
offset: u32,
push_constants: &[u8],
) -> Result<(), BindPushError> {
if offset % 4 != 0 {
return Err(BindPushError::PushConstantsOffsetNotAligned);
}
if push_constants.len() % 4 != 0 {
return Err(BindPushError::PushConstantsSizeNotAligned);
}
let mut current_offset = offset;
let mut remaining_size = push_constants.len() as u32;
for range in pipeline_layout
.push_constant_ranges_disjoint()
.iter()
.skip_while(|range| range.offset + range.size <= offset)
{
if range.offset > current_offset {
break;
}
let push_size = remaining_size.min(range.offset + range.size - current_offset);
current_offset += push_size;
remaining_size -= push_size;
if remaining_size == 0 {
break;
}
}
if remaining_size != 0 {
return Err(BindPushError::PushConstantsDataOutOfRange {
offset: current_offset,
});
}
Ok(())
}
pub fn push_descriptor_set(
&mut self,
pipeline_bind_point: PipelineBindPoint,
pipeline_layout: Arc<PipelineLayout>,
set_num: u32,
descriptor_writes: impl IntoIterator<Item = WriteDescriptorSet>,
) -> &mut Self {
let descriptor_writes: SmallVec<[_; 8]> = descriptor_writes.into_iter().collect();
self.validate_push_descriptor_set(
pipeline_bind_point,
&pipeline_layout,
set_num,
&descriptor_writes,
)
.unwrap();
unsafe {
self.inner.push_descriptor_set(
pipeline_bind_point,
pipeline_layout,
set_num,
descriptor_writes,
);
}
self
}
fn validate_push_descriptor_set(
&self,
pipeline_bind_point: PipelineBindPoint,
pipeline_layout: &PipelineLayout,
set_num: u32,
descriptor_writes: &[WriteDescriptorSet],
) -> Result<(), BindPushError> {
if !self.device().enabled_extensions().khr_push_descriptor {
return Err(BindPushError::RequirementNotMet {
required_for: "`push_descriptor_set`",
requires_one_of: RequiresOneOf {
device_extensions: &["khr_push_descriptor"],
..Default::default()
},
});
}
pipeline_bind_point.validate_device(self.device())?;
let queue_family_properties = self.queue_family_properties();
match pipeline_bind_point {
PipelineBindPoint::Compute => {
if !queue_family_properties.queue_flags.compute {
return Err(BindPushError::NotSupportedByQueueFamily);
}
}
PipelineBindPoint::Graphics => {
if !queue_family_properties.queue_flags.graphics {
return Err(BindPushError::NotSupportedByQueueFamily);
}
}
}
assert_eq!(self.device(), pipeline_layout.device());
if set_num as usize > pipeline_layout.set_layouts().len() {
return Err(BindPushError::DescriptorSetOutOfRange {
set_num,
pipeline_layout_set_count: pipeline_layout.set_layouts().len() as u32,
});
}
let descriptor_set_layout = &pipeline_layout.set_layouts()[set_num as usize];
if !descriptor_set_layout.push_descriptor() {
return Err(BindPushError::DescriptorSetNotPush { set_num });
}
for write in descriptor_writes {
check_descriptor_write(write, descriptor_set_layout, 0)?;
}
Ok(())
}
}
impl SyncCommandBufferBuilder {
#[inline]
pub fn bind_descriptor_sets(&mut self) -> SyncCommandBufferBuilderBindDescriptorSets<'_> {
SyncCommandBufferBuilderBindDescriptorSets {
builder: self,
descriptor_sets: SmallVec::new(),
}
}
#[inline]
pub unsafe fn bind_index_buffer(
&mut self,
buffer: Arc<dyn BufferAccess>,
index_type: IndexType,
) {
struct Cmd {
buffer: Arc<dyn BufferAccess>,
index_type: IndexType,
}
impl Command for Cmd {
fn name(&self) -> &'static str {
"bind_index_buffer"
}
unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
out.bind_index_buffer(self.buffer.as_ref(), self.index_type);
}
}
self.current_state.index_buffer = Some((buffer.clone(), index_type));
self.commands.push(Box::new(Cmd { buffer, index_type }));
}
#[inline]
pub unsafe fn bind_pipeline_compute(&mut self, pipeline: Arc<ComputePipeline>) {
struct Cmd {
pipeline: Arc<ComputePipeline>,
}
impl Command for Cmd {
fn name(&self) -> &'static str {
"bind_pipeline_compute"
}
unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
out.bind_pipeline_compute(&self.pipeline);
}
}
self.current_state.pipeline_compute = Some(pipeline.clone());
self.commands.push(Box::new(Cmd { pipeline }));
}
#[inline]
pub unsafe fn bind_pipeline_graphics(&mut self, pipeline: Arc<GraphicsPipeline>) {
struct Cmd {
pipeline: Arc<GraphicsPipeline>,
}
impl Command for Cmd {
fn name(&self) -> &'static str {
"bind_pipeline_graphics"
}
unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
out.bind_pipeline_graphics(&self.pipeline);
}
}
self.current_state.reset_dynamic_states(
pipeline
.dynamic_states()
.filter(|(_, d)| !d) .map(|(s, _)| s),
);
self.current_state.pipeline_graphics = Some(pipeline.clone());
self.commands.push(Box::new(Cmd { pipeline }));
}
#[inline]
pub fn bind_vertex_buffers(&mut self) -> SyncCommandBufferBuilderBindVertexBuffer<'_> {
SyncCommandBufferBuilderBindVertexBuffer {
builder: self,
inner: UnsafeCommandBufferBuilderBindVertexBuffer::new(),
buffers: SmallVec::new(),
}
}
pub unsafe fn push_constants<D>(
&mut self,
pipeline_layout: Arc<PipelineLayout>,
stages: ShaderStages,
offset: u32,
size: u32,
data: &D,
) where
D: ?Sized + Send + Sync + 'static,
{
struct Cmd {
pipeline_layout: Arc<PipelineLayout>,
stages: ShaderStages,
offset: u32,
size: u32,
data: Box<[u8]>,
}
impl Command for Cmd {
fn name(&self) -> &'static str {
"push_constants"
}
unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
out.push_constants::<[u8]>(
&self.pipeline_layout,
self.stages,
self.offset,
self.size,
&self.data,
);
}
}
debug_assert!(size_of_val(data) >= size as usize);
let mut out = Vec::with_capacity(size as usize);
ptr::copy::<u8>(
data as *const D as *const u8,
out.as_mut_ptr(),
size as usize,
);
out.set_len(size as usize);
self.commands.push(Box::new(Cmd {
pipeline_layout: pipeline_layout.clone(),
stages,
offset,
size,
data: out.into(),
}));
self.current_state
.push_constants
.insert(offset..offset + size);
self.current_state.push_constants_pipeline_layout = Some(pipeline_layout);
}
pub unsafe fn push_descriptor_set(
&mut self,
pipeline_bind_point: PipelineBindPoint,
pipeline_layout: Arc<PipelineLayout>,
set_num: u32,
descriptor_writes: impl IntoIterator<Item = WriteDescriptorSet>,
) {
struct Cmd {
pipeline_bind_point: PipelineBindPoint,
pipeline_layout: Arc<PipelineLayout>,
set_num: u32,
descriptor_writes: SmallVec<[WriteDescriptorSet; 8]>,
}
impl Command for Cmd {
fn name(&self) -> &'static str {
"push_descriptor_set"
}
unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
out.push_descriptor_set(
self.pipeline_bind_point,
&self.pipeline_layout,
self.set_num,
&self.descriptor_writes,
);
}
}
let descriptor_writes: SmallVec<[WriteDescriptorSet; 8]> =
descriptor_writes.into_iter().collect();
let state = self.current_state.invalidate_descriptor_sets(
pipeline_bind_point,
pipeline_layout.clone(),
set_num,
1,
);
let layout = state.pipeline_layout.set_layouts()[set_num as usize].as_ref();
debug_assert!(layout.push_descriptor());
let set_resources = match state
.descriptor_sets
.entry(set_num)
.or_insert_with(|| SetOrPush::Push(DescriptorSetResources::new(layout, 0)))
{
SetOrPush::Push(set_resources) => set_resources,
_ => unreachable!(),
};
for write in &descriptor_writes {
set_resources.update(write);
}
self.commands.push(Box::new(Cmd {
pipeline_bind_point,
pipeline_layout,
set_num,
descriptor_writes,
}));
}
}
pub struct SyncCommandBufferBuilderBindDescriptorSets<'b> {
builder: &'b mut SyncCommandBufferBuilder,
descriptor_sets: SmallVec<[DescriptorSetWithOffsets; 12]>,
}
impl<'b> SyncCommandBufferBuilderBindDescriptorSets<'b> {
pub fn add(&mut self, descriptor_set: impl Into<DescriptorSetWithOffsets>) {
self.descriptor_sets.push(descriptor_set.into());
}
#[inline]
pub unsafe fn submit(
self,
pipeline_bind_point: PipelineBindPoint,
pipeline_layout: Arc<PipelineLayout>,
first_set: u32,
) {
if self.descriptor_sets.is_empty() {
return;
}
struct Cmd {
descriptor_sets: SmallVec<[DescriptorSetWithOffsets; 12]>,
pipeline_bind_point: PipelineBindPoint,
pipeline_layout: Arc<PipelineLayout>,
first_set: u32,
}
impl Command for Cmd {
fn name(&self) -> &'static str {
"bind_descriptor_sets"
}
unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
let descriptor_sets = self.descriptor_sets.iter().map(|x| x.as_ref().0.inner());
let dynamic_offsets = self
.descriptor_sets
.iter()
.flat_map(|x| x.as_ref().1.iter().copied());
out.bind_descriptor_sets(
self.pipeline_bind_point,
&self.pipeline_layout,
self.first_set,
descriptor_sets,
dynamic_offsets,
);
}
}
let state = self.builder.current_state.invalidate_descriptor_sets(
pipeline_bind_point,
pipeline_layout.clone(),
first_set,
self.descriptor_sets.len() as u32,
);
for (set_num, set) in self.descriptor_sets.iter().enumerate() {
state
.descriptor_sets
.insert(first_set + set_num as u32, SetOrPush::Set(set.clone()));
}
self.builder.commands.push(Box::new(Cmd {
descriptor_sets: self.descriptor_sets,
pipeline_bind_point,
pipeline_layout,
first_set,
}));
}
}
pub struct SyncCommandBufferBuilderBindVertexBuffer<'a> {
builder: &'a mut SyncCommandBufferBuilder,
inner: UnsafeCommandBufferBuilderBindVertexBuffer,
buffers: SmallVec<[Arc<dyn BufferAccess>; 4]>,
}
impl<'a> SyncCommandBufferBuilderBindVertexBuffer<'a> {
#[inline]
pub fn add(&mut self, buffer: Arc<dyn BufferAccess>) {
self.inner.add(buffer.as_ref());
self.buffers.push(buffer);
}
#[inline]
pub unsafe fn submit(self, first_set: u32) {
struct Cmd {
first_set: u32,
inner: Mutex<Option<UnsafeCommandBufferBuilderBindVertexBuffer>>,
_buffers: SmallVec<[Arc<dyn BufferAccess>; 4]>,
}
impl Command for Cmd {
fn name(&self) -> &'static str {
"bind_vertex_buffers"
}
unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
out.bind_vertex_buffers(self.first_set, self.inner.lock().take().unwrap());
}
}
for (i, buffer) in self.buffers.iter().enumerate() {
self.builder
.current_state
.vertex_buffers
.insert(first_set + i as u32, buffer.clone());
}
self.builder.commands.push(Box::new(Cmd {
first_set,
inner: Mutex::new(Some(self.inner)),
_buffers: self.buffers,
}));
}
}
impl UnsafeCommandBufferBuilder {
#[inline]
pub unsafe fn bind_descriptor_sets<'s>(
&mut self,
pipeline_bind_point: PipelineBindPoint,
pipeline_layout: &PipelineLayout,
first_set: u32,
sets: impl IntoIterator<Item = &'s UnsafeDescriptorSet>,
dynamic_offsets: impl IntoIterator<Item = u32>,
) {
let fns = self.device.fns();
let sets: SmallVec<[_; 12]> = sets.into_iter().map(|s| s.handle()).collect();
if sets.is_empty() {
return;
}
let dynamic_offsets: SmallVec<[u32; 32]> = dynamic_offsets.into_iter().collect();
let num_bindings = sets.len() as u32;
debug_assert!(first_set + num_bindings <= pipeline_layout.set_layouts().len() as u32);
(fns.v1_0.cmd_bind_descriptor_sets)(
self.handle,
pipeline_bind_point.into(),
pipeline_layout.handle(),
first_set,
num_bindings,
sets.as_ptr(),
dynamic_offsets.len() as u32,
dynamic_offsets.as_ptr(),
);
}
#[inline]
pub unsafe fn bind_index_buffer(&mut self, buffer: &dyn BufferAccess, index_type: IndexType) {
let fns = self.device.fns();
let inner = buffer.inner();
debug_assert!(inner.offset < inner.buffer.size());
debug_assert!(inner.buffer.usage().index_buffer);
(fns.v1_0.cmd_bind_index_buffer)(
self.handle,
inner.buffer.handle(),
inner.offset,
index_type.into(),
);
}
#[inline]
pub unsafe fn bind_pipeline_compute(&mut self, pipeline: &ComputePipeline) {
let fns = self.device.fns();
(fns.v1_0.cmd_bind_pipeline)(
self.handle,
ash::vk::PipelineBindPoint::COMPUTE,
pipeline.handle(),
);
}
#[inline]
pub unsafe fn bind_pipeline_graphics(&mut self, pipeline: &GraphicsPipeline) {
let fns = self.device.fns();
(fns.v1_0.cmd_bind_pipeline)(
self.handle,
ash::vk::PipelineBindPoint::GRAPHICS,
pipeline.handle(),
);
}
#[inline]
pub unsafe fn bind_vertex_buffers(
&mut self,
first_binding: u32,
params: UnsafeCommandBufferBuilderBindVertexBuffer,
) {
debug_assert_eq!(params.raw_buffers.len(), params.offsets.len());
if params.raw_buffers.is_empty() {
return;
}
let fns = self.device.fns();
let num_bindings = params.raw_buffers.len() as u32;
debug_assert!({
let max_bindings = self
.device
.physical_device()
.properties()
.max_vertex_input_bindings;
first_binding + num_bindings <= max_bindings
});
(fns.v1_0.cmd_bind_vertex_buffers)(
self.handle,
first_binding,
num_bindings,
params.raw_buffers.as_ptr(),
params.offsets.as_ptr(),
);
}
pub unsafe fn push_constants<D>(
&mut self,
pipeline_layout: &PipelineLayout,
stages: ShaderStages,
offset: u32,
size: u32,
data: &D,
) where
D: BufferContents + ?Sized,
{
let fns = self.device.fns();
debug_assert!(!stages.is_empty());
debug_assert!(size > 0);
debug_assert_eq!(size % 4, 0);
debug_assert_eq!(offset % 4, 0);
debug_assert!(size_of_val(data) >= size as usize);
(fns.v1_0.cmd_push_constants)(
self.handle,
pipeline_layout.handle(),
stages.into(),
offset as u32,
size as u32,
data.as_bytes().as_ptr() as *const _,
);
}
pub unsafe fn push_descriptor_set<'a>(
&mut self,
pipeline_bind_point: PipelineBindPoint,
pipeline_layout: &PipelineLayout,
set_num: u32,
descriptor_writes: impl IntoIterator<Item = &'a WriteDescriptorSet>,
) {
debug_assert!(self.device.enabled_extensions().khr_push_descriptor);
let (infos, mut writes): (SmallVec<[_; 8]>, SmallVec<[_; 8]>) = descriptor_writes
.into_iter()
.map(|write| {
let binding =
&pipeline_layout.set_layouts()[set_num as usize].bindings()[&write.binding()];
(
write.to_vulkan_info(binding.descriptor_type),
write.to_vulkan(ash::vk::DescriptorSet::null(), binding.descriptor_type),
)
})
.unzip();
if writes.is_empty() {
return;
}
for (info, write) in infos.iter().zip(writes.iter_mut()) {
match info {
DescriptorWriteInfo::Image(info) => {
write.descriptor_count = info.len() as u32;
write.p_image_info = info.as_ptr();
}
DescriptorWriteInfo::Buffer(info) => {
write.descriptor_count = info.len() as u32;
write.p_buffer_info = info.as_ptr();
}
DescriptorWriteInfo::BufferView(info) => {
write.descriptor_count = info.len() as u32;
write.p_texel_buffer_view = info.as_ptr();
}
}
debug_assert!(write.descriptor_count != 0);
}
let fns = self.device.fns();
(fns.khr_push_descriptor.cmd_push_descriptor_set_khr)(
self.handle,
pipeline_bind_point.into(),
pipeline_layout.handle(),
set_num,
writes.len() as u32,
writes.as_ptr(),
);
}
}
#[derive(Debug)]
pub struct UnsafeCommandBufferBuilderBindVertexBuffer {
pub raw_buffers: SmallVec<[ash::vk::Buffer; 4]>,
pub offsets: SmallVec<[DeviceSize; 4]>,
}
impl UnsafeCommandBufferBuilderBindVertexBuffer {
#[inline]
pub fn new() -> UnsafeCommandBufferBuilderBindVertexBuffer {
UnsafeCommandBufferBuilderBindVertexBuffer {
raw_buffers: SmallVec::new(),
offsets: SmallVec::new(),
}
}
#[inline]
pub fn add(&mut self, buffer: &dyn BufferAccess) {
let inner = buffer.inner();
debug_assert!(inner.buffer.usage().vertex_buffer);
self.raw_buffers.push(inner.buffer.handle());
self.offsets.push(inner.offset);
}
}
#[derive(Clone, Debug)]
enum BindPushError {
DescriptorSetUpdateError(DescriptorSetUpdateError),
RequirementNotMet {
required_for: &'static str,
requires_one_of: RequiresOneOf,
},
DescriptorSetNotCompatible {
set_num: u32,
},
DescriptorSetNotPush {
set_num: u32,
},
DescriptorSetOutOfRange {
set_num: u32,
pipeline_layout_set_count: u32,
},
IndexBufferMissingUsage,
MaxVertexInputBindingsExceeded {
_binding_count: u32,
_max: u32,
},
NotSupportedByQueueFamily,
PreviousPipelineColorAttachmentFormatMismatch,
PreviousPipelineDepthAttachmentFormatMismatch,
PreviousPipelineStencilAttachmentFormatMismatch,
PushConstantsDataOutOfRange {
offset: u32,
},
PushConstantsOffsetNotAligned,
PushConstantsSizeNotAligned,
VertexBufferMissingUsage,
}
impl error::Error for BindPushError {
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
match self {
BindPushError::DescriptorSetUpdateError(err) => Some(err),
_ => None,
}
}
}
impl Display for BindPushError {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
match self {
Self::RequirementNotMet {
required_for,
requires_one_of,
} => write!(
f,
"a requirement was not met for: {}; requires one of: {}",
required_for, requires_one_of,
),
Self::DescriptorSetUpdateError(_) => write!(f, "a DescriptorSetUpdateError"),
Self::DescriptorSetNotCompatible { set_num } => write!(
f,
"the element of `descriptor_sets` being bound to slot {} is not compatible with \
the corresponding slot in `pipeline_layout`",
set_num,
),
Self::DescriptorSetNotPush { set_num } => write!(
f,
"the descriptor set number being pushed ({}) is not defined for push descriptor \
sets in the pipeline layout",
set_num,
),
Self::DescriptorSetOutOfRange {
set_num,
pipeline_layout_set_count,
} => write!(
f,
"the highest descriptor set slot being bound ({}) is greater than the number of \
sets in `pipeline_layout` ({})",
set_num, pipeline_layout_set_count,
),
Self::IndexBufferMissingUsage => {
write!(f, "an index buffer is missing the `index_buffer` usage")
}
Self::MaxVertexInputBindingsExceeded { .. } => {
write!(f, "the `max_vertex_input_bindings` limit has been exceeded")
}
Self::NotSupportedByQueueFamily => {
write!(f, "the queue family doesn't allow this operation")
}
Self::PreviousPipelineColorAttachmentFormatMismatch => write!(
f,
"the newly set pipeline has color attachment formats that do not match the \
previously used pipeline",
),
Self::PreviousPipelineDepthAttachmentFormatMismatch => write!(
f,
"the newly set pipeline has a depth attachment format that does not match the \
previously used pipeline",
),
Self::PreviousPipelineStencilAttachmentFormatMismatch => write!(
f,
"the newly set pipeline has a stencil attachment format that does not match the \
previously used pipeline",
),
Self::PushConstantsDataOutOfRange { offset } => write!(
f,
"the push constants data to be written at offset {} is not included in any push \
constant range of the pipeline layout",
offset,
),
Self::PushConstantsOffsetNotAligned => {
write!(f, "the push constants offset is not a multiple of 4")
}
Self::PushConstantsSizeNotAligned => {
write!(f, "the push constants size is not a multiple of 4")
}
Self::VertexBufferMissingUsage => {
write!(f, "a vertex buffer is missing the `vertex_buffer` usage")
}
}
}
}
impl From<DescriptorSetUpdateError> for BindPushError {
fn from(err: DescriptorSetUpdateError) -> Self {
Self::DescriptorSetUpdateError(err)
}
}
impl From<RequirementNotMet> for BindPushError {
fn from(err: RequirementNotMet) -> Self {
Self::RequirementNotMet {
required_for: err.required_for,
requires_one_of: err.requires_one_of,
}
}
}