| // Copyright (c) 2016 The vulkano developers |
| // Licensed under the Apache License, Version 2.0 |
| // <LICENSE-APACHE or |
| // https://www.apache.org/licenses/LICENSE-2.0> or the MIT |
| // license <LICENSE-MIT or https://opensource.org/licenses/MIT>, |
| // at your option. All files in the project carrying such |
| // notice may not be copied, modified, or distributed except |
| // according to those terms. |
| |
| use super::Command; |
| use crate::buffer::BufferAccess; |
| use crate::buffer::TypedBufferAccess; |
| use crate::command_buffer::synced::builder::KeyTy; |
| use crate::command_buffer::synced::builder::SyncCommandBufferBuilder; |
| use crate::command_buffer::synced::builder::SyncCommandBufferBuilderError; |
| use crate::command_buffer::sys::UnsafeCommandBufferBuilder; |
| use crate::command_buffer::sys::UnsafeCommandBufferBuilderBindVertexBuffer; |
| use crate::command_buffer::sys::UnsafeCommandBufferBuilderBufferImageCopy; |
| use crate::command_buffer::sys::UnsafeCommandBufferBuilderColorImageClear; |
| use crate::command_buffer::sys::UnsafeCommandBufferBuilderExecuteCommands; |
| use crate::command_buffer::sys::UnsafeCommandBufferBuilderImageBlit; |
| use crate::command_buffer::sys::UnsafeCommandBufferBuilderImageCopy; |
| use crate::command_buffer::CommandBufferExecError; |
| use crate::command_buffer::ImageUninitializedSafe; |
| use crate::command_buffer::SecondaryCommandBuffer; |
| use crate::command_buffer::SubpassContents; |
| use crate::descriptor_set::layout::DescriptorDescTy; |
| use crate::descriptor_set::DescriptorSet; |
| use crate::descriptor_set::DescriptorSetWithOffsets; |
| use crate::format::ClearValue; |
| use crate::image::ImageAccess; |
| use crate::image::ImageLayout; |
| use crate::pipeline::depth_stencil::StencilFaces; |
| use crate::pipeline::input_assembly::IndexType; |
| use crate::pipeline::layout::PipelineLayout; |
| use crate::pipeline::shader::ShaderStages; |
| use crate::pipeline::vertex::VertexInput; |
| use crate::pipeline::viewport::Scissor; |
| use crate::pipeline::viewport::Viewport; |
| use crate::pipeline::ComputePipelineAbstract; |
| use crate::pipeline::GraphicsPipelineAbstract; |
| use crate::pipeline::PipelineBindPoint; |
| use crate::query::QueryControlFlags; |
| use crate::query::QueryPool; |
| use crate::query::QueryResultElement; |
| use crate::query::QueryResultFlags; |
| use crate::render_pass::FramebufferAbstract; |
| use crate::render_pass::LoadOp; |
| use crate::sampler::Filter; |
| use crate::sync::AccessFlags; |
| use crate::sync::Event; |
| use crate::sync::PipelineMemoryAccess; |
| use crate::sync::PipelineStage; |
| use crate::sync::PipelineStages; |
| use crate::DeviceSize; |
| use crate::SafeDeref; |
| use crate::VulkanObject; |
| use smallvec::SmallVec; |
| use std::borrow::Cow; |
| use std::ffi::CStr; |
| use std::mem; |
| use std::ops::Range; |
| use std::ptr; |
| use std::sync::{Arc, Mutex}; |
| |
| impl SyncCommandBufferBuilder { |
| /// Calls `vkCmdBeginQuery` on the builder. |
| #[inline] |
| pub unsafe fn begin_query( |
| &mut self, |
| query_pool: Arc<QueryPool>, |
| query: u32, |
| flags: QueryControlFlags, |
| ) { |
| struct Cmd { |
| query_pool: Arc<QueryPool>, |
| query: u32, |
| flags: QueryControlFlags, |
| } |
| |
| impl Command for Cmd { |
| fn name(&self) -> &'static str { |
| "vkCmdBeginQuery" |
| } |
| |
| unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) { |
| out.begin_query(self.query_pool.query(self.query).unwrap(), self.flags); |
| } |
| } |
| |
| self.append_command( |
| Cmd { |
| query_pool, |
| query, |
| flags, |
| }, |
| &[], |
| ) |
| .unwrap(); |
| } |
| |
| /// Calls `vkBeginRenderPass` on the builder. |
| // TODO: it shouldn't be possible to get an error if the framebuffer checked conflicts already |
| // TODO: after begin_render_pass has been called, flushing should be forbidden and an error |
| // returned if conflict |
| #[inline] |
| pub unsafe fn begin_render_pass<F, I>( |
| &mut self, |
| framebuffer: F, |
| subpass_contents: SubpassContents, |
| clear_values: I, |
| ) -> Result<(), SyncCommandBufferBuilderError> |
| where |
| F: FramebufferAbstract + Send + Sync + 'static, |
| I: IntoIterator<Item = ClearValue> + Send + Sync + 'static, |
| { |
| struct Cmd<F, I> { |
| framebuffer: F, |
| subpass_contents: SubpassContents, |
| clear_values: Mutex<Option<I>>, |
| } |
| |
| impl<F, I> Command for Cmd<F, I> |
| where |
| F: FramebufferAbstract + Send + Sync + 'static, |
| I: IntoIterator<Item = ClearValue>, |
| { |
| fn name(&self) -> &'static str { |
| "vkCmdBeginRenderPass" |
| } |
| |
| unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) { |
| out.begin_render_pass( |
| &self.framebuffer, |
| self.subpass_contents, |
| self.clear_values.lock().unwrap().take().unwrap(), |
| ); |
| } |
| |
| fn image(&self, num: usize) -> &dyn ImageAccess { |
| self.framebuffer.attached_image_view(num).unwrap().image() |
| } |
| |
| fn image_name(&self, num: usize) -> Cow<'static, str> { |
| format!("attachment {}", num).into() |
| } |
| } |
| |
| let resources = framebuffer |
| .render_pass() |
| .desc() |
| .attachments() |
| .iter() |
| .map(|desc| { |
| ( |
| KeyTy::Image, |
| Some(( |
| PipelineMemoryAccess { |
| stages: PipelineStages { |
| all_commands: true, |
| ..PipelineStages::none() |
| }, // TODO: wrong! |
| access: AccessFlags { |
| input_attachment_read: true, |
| color_attachment_read: true, |
| color_attachment_write: true, |
| depth_stencil_attachment_read: true, |
| depth_stencil_attachment_write: true, |
| ..AccessFlags::none() |
| }, // TODO: suboptimal |
| exclusive: true, // TODO: suboptimal ; note: remember to always pass true if desc.initial_layout != desc.final_layout |
| }, |
| desc.initial_layout, |
| desc.final_layout, |
| match desc.initial_layout != ImageLayout::Undefined |
| || desc.load == LoadOp::Clear |
| { |
| true => ImageUninitializedSafe::Safe, |
| false => ImageUninitializedSafe::Unsafe, |
| }, |
| )), |
| ) |
| }) |
| .collect::<Vec<_>>(); |
| |
| self.append_command( |
| Cmd { |
| framebuffer, |
| subpass_contents, |
| clear_values: Mutex::new(Some(clear_values)), |
| }, |
| &resources, |
| )?; |
| |
| self.latest_render_pass_enter = Some(self.commands.len() - 1); |
| Ok(()) |
| } |
| |
| /// Starts the process of binding descriptor sets. Returns an intermediate struct which can be |
| /// used to add the sets. |
| #[inline] |
| pub fn bind_descriptor_sets(&mut self) -> SyncCommandBufferBuilderBindDescriptorSets { |
| SyncCommandBufferBuilderBindDescriptorSets { |
| builder: self, |
| descriptor_sets: SmallVec::new(), |
| } |
| } |
| |
| /// Calls `vkCmdBindIndexBuffer` on the builder. |
| #[inline] |
| pub unsafe fn bind_index_buffer<B>( |
| &mut self, |
| buffer: B, |
| index_ty: IndexType, |
| ) -> Result<(), SyncCommandBufferBuilderError> |
| where |
| B: BufferAccess + Send + Sync + 'static, |
| { |
| struct Cmd<B> { |
| buffer: B, |
| index_ty: IndexType, |
| } |
| |
| impl<B> Command for Cmd<B> |
| where |
| B: BufferAccess + Send + Sync + 'static, |
| { |
| fn name(&self) -> &'static str { |
| "vkCmdBindIndexBuffer" |
| } |
| |
| unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) { |
| out.bind_index_buffer(&self.buffer, self.index_ty); |
| } |
| |
| fn bound_index_buffer(&self) -> &dyn BufferAccess { |
| &self.buffer |
| } |
| } |
| |
| self.append_command(Cmd { buffer, index_ty }, &[])?; |
| self.bindings.index_buffer = self.commands.last().cloned(); |
| |
| Ok(()) |
| } |
| |
| /// Calls `vkCmdBindPipeline` on the builder with a compute pipeline. |
| #[inline] |
| pub unsafe fn bind_pipeline_compute<Cp>(&mut self, pipeline: Cp) |
| where |
| Cp: ComputePipelineAbstract + Send + Sync + 'static, |
| { |
| struct Cmd<Gp> { |
| pipeline: Gp, |
| } |
| |
| impl<Gp> Command for Cmd<Gp> |
| where |
| Gp: ComputePipelineAbstract + Send + Sync + 'static, |
| { |
| fn name(&self) -> &'static str { |
| "vkCmdBindPipeline" |
| } |
| |
| unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) { |
| out.bind_pipeline_compute(&self.pipeline); |
| } |
| |
| fn bound_pipeline_compute(&self) -> &dyn ComputePipelineAbstract { |
| &self.pipeline |
| } |
| } |
| |
| self.append_command(Cmd { pipeline }, &[]).unwrap(); |
| self.bindings.pipeline_compute = self.commands.last().cloned(); |
| } |
| |
| /// Calls `vkCmdBindPipeline` on the builder with a graphics pipeline. |
| #[inline] |
| pub unsafe fn bind_pipeline_graphics<Gp>(&mut self, pipeline: Gp) |
| where |
| Gp: GraphicsPipelineAbstract + Send + Sync + 'static, |
| { |
| struct Cmd<Gp> { |
| pipeline: Gp, |
| } |
| |
| impl<Gp> Command for Cmd<Gp> |
| where |
| Gp: GraphicsPipelineAbstract + Send + Sync + 'static, |
| { |
| fn name(&self) -> &'static str { |
| "vkCmdBindPipeline" |
| } |
| |
| unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) { |
| out.bind_pipeline_graphics(&self.pipeline); |
| } |
| |
| fn bound_pipeline_graphics(&self) -> &dyn GraphicsPipelineAbstract { |
| &self.pipeline |
| } |
| } |
| |
| self.append_command(Cmd { pipeline }, &[]).unwrap(); |
| self.bindings.pipeline_graphics = self.commands.last().cloned(); |
| } |
| |
| /// Starts the process of binding vertex buffers. Returns an intermediate struct which can be |
| /// used to add the buffers. |
| #[inline] |
| pub fn bind_vertex_buffers(&mut self) -> SyncCommandBufferBuilderBindVertexBuffer { |
| SyncCommandBufferBuilderBindVertexBuffer { |
| builder: self, |
| inner: UnsafeCommandBufferBuilderBindVertexBuffer::new(), |
| buffers: SmallVec::new(), |
| } |
| } |
| |
| /// Calls `vkCmdCopyImage` on the builder. |
| /// |
| /// Does nothing if the list of regions is empty, as it would be a no-op and isn't a valid |
| /// usage of the command anyway. |
| #[inline] |
| pub unsafe fn copy_image<S, D, R>( |
| &mut self, |
| source: S, |
| source_layout: ImageLayout, |
| destination: D, |
| destination_layout: ImageLayout, |
| regions: R, |
| ) -> Result<(), SyncCommandBufferBuilderError> |
| where |
| S: ImageAccess + Send + Sync + 'static, |
| D: ImageAccess + Send + Sync + 'static, |
| R: IntoIterator<Item = UnsafeCommandBufferBuilderImageCopy> + Send + Sync + 'static, |
| { |
| struct Cmd<S, D, R> { |
| source: S, |
| source_layout: ImageLayout, |
| destination: D, |
| destination_layout: ImageLayout, |
| regions: Mutex<Option<R>>, |
| } |
| |
| impl<S, D, R> Command for Cmd<S, D, R> |
| where |
| S: ImageAccess + Send + Sync + 'static, |
| D: ImageAccess + Send + Sync + 'static, |
| R: IntoIterator<Item = UnsafeCommandBufferBuilderImageCopy>, |
| { |
| fn name(&self) -> &'static str { |
| "vkCmdCopyImage" |
| } |
| |
| unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) { |
| out.copy_image( |
| &self.source, |
| self.source_layout, |
| &self.destination, |
| self.destination_layout, |
| self.regions.lock().unwrap().take().unwrap(), |
| ); |
| } |
| |
| fn image(&self, num: usize) -> &dyn ImageAccess { |
| if num == 0 { |
| &self.source |
| } else if num == 1 { |
| &self.destination |
| } else { |
| panic!() |
| } |
| } |
| |
| fn image_name(&self, num: usize) -> Cow<'static, str> { |
| if num == 0 { |
| "source".into() |
| } else if num == 1 { |
| "destination".into() |
| } else { |
| panic!() |
| } |
| } |
| } |
| |
| self.append_command( |
| Cmd { |
| source, |
| source_layout, |
| destination, |
| destination_layout, |
| regions: Mutex::new(Some(regions)), |
| }, |
| &[ |
| ( |
| KeyTy::Image, |
| Some(( |
| PipelineMemoryAccess { |
| stages: PipelineStages { |
| transfer: true, |
| ..PipelineStages::none() |
| }, |
| access: AccessFlags { |
| transfer_read: true, |
| ..AccessFlags::none() |
| }, |
| exclusive: false, |
| }, |
| source_layout, |
| source_layout, |
| ImageUninitializedSafe::Unsafe, |
| )), |
| ), |
| ( |
| KeyTy::Image, |
| Some(( |
| PipelineMemoryAccess { |
| stages: PipelineStages { |
| transfer: true, |
| ..PipelineStages::none() |
| }, |
| access: AccessFlags { |
| transfer_write: true, |
| ..AccessFlags::none() |
| }, |
| exclusive: true, |
| }, |
| destination_layout, |
| destination_layout, |
| ImageUninitializedSafe::Safe, |
| )), |
| ), |
| ], |
| )?; |
| |
| Ok(()) |
| } |
| |
| /// Calls `vkCmdBlitImage` on the builder. |
| /// |
| /// Does nothing if the list of regions is empty, as it would be a no-op and isn't a valid |
| /// usage of the command anyway. |
| #[inline] |
| pub unsafe fn blit_image<S, D, R>( |
| &mut self, |
| source: S, |
| source_layout: ImageLayout, |
| destination: D, |
| destination_layout: ImageLayout, |
| regions: R, |
| filter: Filter, |
| ) -> Result<(), SyncCommandBufferBuilderError> |
| where |
| S: ImageAccess + Send + Sync + 'static, |
| D: ImageAccess + Send + Sync + 'static, |
| R: IntoIterator<Item = UnsafeCommandBufferBuilderImageBlit> + Send + Sync + 'static, |
| { |
| struct Cmd<S, D, R> { |
| source: S, |
| source_layout: ImageLayout, |
| destination: D, |
| destination_layout: ImageLayout, |
| regions: Mutex<Option<R>>, |
| filter: Filter, |
| } |
| |
| impl<S, D, R> Command for Cmd<S, D, R> |
| where |
| S: ImageAccess + Send + Sync + 'static, |
| D: ImageAccess + Send + Sync + 'static, |
| R: IntoIterator<Item = UnsafeCommandBufferBuilderImageBlit>, |
| { |
| fn name(&self) -> &'static str { |
| "vkCmdBlitImage" |
| } |
| |
| unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) { |
| out.blit_image( |
| &self.source, |
| self.source_layout, |
| &self.destination, |
| self.destination_layout, |
| self.regions.lock().unwrap().take().unwrap(), |
| self.filter, |
| ); |
| } |
| |
| fn image(&self, num: usize) -> &dyn ImageAccess { |
| if num == 0 { |
| &self.source |
| } else if num == 1 { |
| &self.destination |
| } else { |
| panic!() |
| } |
| } |
| |
| fn image_name(&self, num: usize) -> Cow<'static, str> { |
| if num == 0 { |
| "source".into() |
| } else if num == 1 { |
| "destination".into() |
| } else { |
| panic!() |
| } |
| } |
| } |
| |
| self.append_command( |
| Cmd { |
| source, |
| source_layout, |
| destination, |
| destination_layout, |
| regions: Mutex::new(Some(regions)), |
| filter, |
| }, |
| &[ |
| ( |
| KeyTy::Image, |
| Some(( |
| PipelineMemoryAccess { |
| stages: PipelineStages { |
| transfer: true, |
| ..PipelineStages::none() |
| }, |
| access: AccessFlags { |
| transfer_read: true, |
| ..AccessFlags::none() |
| }, |
| exclusive: false, |
| }, |
| source_layout, |
| source_layout, |
| ImageUninitializedSafe::Unsafe, |
| )), |
| ), |
| ( |
| KeyTy::Image, |
| Some(( |
| PipelineMemoryAccess { |
| stages: PipelineStages { |
| transfer: true, |
| ..PipelineStages::none() |
| }, |
| access: AccessFlags { |
| transfer_write: true, |
| ..AccessFlags::none() |
| }, |
| exclusive: true, |
| }, |
| destination_layout, |
| destination_layout, |
| ImageUninitializedSafe::Safe, |
| )), |
| ), |
| ], |
| )?; |
| |
| Ok(()) |
| } |
| |
| /// Calls `vkCmdClearColorImage` on the builder. |
| /// |
| /// Does nothing if the list of regions is empty, as it would be a no-op and isn't a valid |
| /// usage of the command anyway. |
| pub unsafe fn clear_color_image<I, R>( |
| &mut self, |
| image: I, |
| layout: ImageLayout, |
| color: ClearValue, |
| regions: R, |
| ) -> Result<(), SyncCommandBufferBuilderError> |
| where |
| I: ImageAccess + Send + Sync + 'static, |
| R: IntoIterator<Item = UnsafeCommandBufferBuilderColorImageClear> + Send + Sync + 'static, |
| { |
| struct Cmd<I, R> { |
| image: I, |
| layout: ImageLayout, |
| color: ClearValue, |
| regions: Mutex<Option<R>>, |
| } |
| |
| impl<I, R> Command for Cmd<I, R> |
| where |
| I: ImageAccess + Send + Sync + 'static, |
| R: IntoIterator<Item = UnsafeCommandBufferBuilderColorImageClear> |
| + Send |
| + Sync |
| + 'static, |
| { |
| fn name(&self) -> &'static str { |
| "vkCmdClearColorImage" |
| } |
| |
| unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) { |
| out.clear_color_image( |
| &self.image, |
| self.layout, |
| self.color, |
| self.regions.lock().unwrap().take().unwrap(), |
| ); |
| } |
| |
| fn image(&self, num: usize) -> &dyn ImageAccess { |
| assert_eq!(num, 0); |
| &self.image |
| } |
| |
| fn image_name(&self, num: usize) -> Cow<'static, str> { |
| assert_eq!(num, 0); |
| "target".into() |
| } |
| } |
| |
| self.append_command( |
| Cmd { |
| image, |
| layout, |
| color, |
| regions: Mutex::new(Some(regions)), |
| }, |
| &[( |
| KeyTy::Image, |
| Some(( |
| PipelineMemoryAccess { |
| stages: PipelineStages { |
| transfer: true, |
| ..PipelineStages::none() |
| }, |
| access: AccessFlags { |
| transfer_write: true, |
| ..AccessFlags::none() |
| }, |
| exclusive: true, |
| }, |
| layout, |
| layout, |
| ImageUninitializedSafe::Safe, |
| )), |
| )], |
| )?; |
| |
| Ok(()) |
| } |
| |
| /// Calls `vkCmdCopyBuffer` on the builder. |
| /// |
| /// Does nothing if the list of regions is empty, as it would be a no-op and isn't a valid |
| /// usage of the command anyway. |
| #[inline] |
| pub unsafe fn copy_buffer<S, D, R>( |
| &mut self, |
| source: S, |
| destination: D, |
| regions: R, |
| ) -> Result<(), SyncCommandBufferBuilderError> |
| where |
| S: BufferAccess + Send + Sync + 'static, |
| D: BufferAccess + Send + Sync + 'static, |
| R: IntoIterator<Item = (DeviceSize, DeviceSize, DeviceSize)> + Send + Sync + 'static, |
| { |
| struct Cmd<S, D, R> { |
| source: S, |
| destination: D, |
| regions: Mutex<Option<R>>, |
| } |
| |
| impl<S, D, R> Command for Cmd<S, D, R> |
| where |
| S: BufferAccess + Send + Sync + 'static, |
| D: BufferAccess + Send + Sync + 'static, |
| R: IntoIterator<Item = (DeviceSize, DeviceSize, DeviceSize)>, |
| { |
| fn name(&self) -> &'static str { |
| "vkCmdCopyBuffer" |
| } |
| |
| unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) { |
| out.copy_buffer( |
| &self.source, |
| &self.destination, |
| self.regions.lock().unwrap().take().unwrap(), |
| ); |
| } |
| |
| fn buffer(&self, num: usize) -> &dyn BufferAccess { |
| match num { |
| 0 => &self.source, |
| 1 => &self.destination, |
| _ => panic!(), |
| } |
| } |
| |
| fn buffer_name(&self, num: usize) -> Cow<'static, str> { |
| match num { |
| 0 => "source".into(), |
| 1 => "destination".into(), |
| _ => panic!(), |
| } |
| } |
| } |
| |
| self.append_command( |
| Cmd { |
| source, |
| destination, |
| regions: Mutex::new(Some(regions)), |
| }, |
| &[ |
| ( |
| KeyTy::Buffer, |
| Some(( |
| PipelineMemoryAccess { |
| stages: PipelineStages { |
| transfer: true, |
| ..PipelineStages::none() |
| }, |
| access: AccessFlags { |
| transfer_read: true, |
| ..AccessFlags::none() |
| }, |
| exclusive: false, |
| }, |
| ImageLayout::Undefined, |
| ImageLayout::Undefined, |
| ImageUninitializedSafe::Unsafe, |
| )), |
| ), |
| ( |
| KeyTy::Buffer, |
| Some(( |
| PipelineMemoryAccess { |
| stages: PipelineStages { |
| transfer: true, |
| ..PipelineStages::none() |
| }, |
| access: AccessFlags { |
| transfer_write: true, |
| ..AccessFlags::none() |
| }, |
| exclusive: true, |
| }, |
| ImageLayout::Undefined, |
| ImageLayout::Undefined, |
| ImageUninitializedSafe::Unsafe, |
| )), |
| ), |
| ], |
| )?; |
| |
| Ok(()) |
| } |
| |
| /// Calls `vkCmdCopyBufferToImage` on the builder. |
| /// |
| /// Does nothing if the list of regions is empty, as it would be a no-op and isn't a valid |
| /// usage of the command anyway. |
| #[inline] |
| pub unsafe fn copy_buffer_to_image<S, D, R>( |
| &mut self, |
| source: S, |
| destination: D, |
| destination_layout: ImageLayout, |
| regions: R, |
| ) -> Result<(), SyncCommandBufferBuilderError> |
| where |
| S: BufferAccess + Send + Sync + 'static, |
| D: ImageAccess + Send + Sync + 'static, |
| R: IntoIterator<Item = UnsafeCommandBufferBuilderBufferImageCopy> + Send + Sync + 'static, |
| { |
| struct Cmd<S, D, R> { |
| source: S, |
| destination: D, |
| destination_layout: ImageLayout, |
| regions: Mutex<Option<R>>, |
| } |
| |
| impl<S, D, R> Command for Cmd<S, D, R> |
| where |
| S: BufferAccess + Send + Sync + 'static, |
| D: ImageAccess + Send + Sync + 'static, |
| R: IntoIterator<Item = UnsafeCommandBufferBuilderBufferImageCopy>, |
| { |
| fn name(&self) -> &'static str { |
| "vkCmdCopyBufferToImage" |
| } |
| |
| unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) { |
| out.copy_buffer_to_image( |
| &self.source, |
| &self.destination, |
| self.destination_layout, |
| self.regions.lock().unwrap().take().unwrap(), |
| ); |
| } |
| |
| fn buffer(&self, num: usize) -> &dyn BufferAccess { |
| assert_eq!(num, 0); |
| &self.source |
| } |
| |
| fn buffer_name(&self, num: usize) -> Cow<'static, str> { |
| assert_eq!(num, 0); |
| "source".into() |
| } |
| |
| fn image(&self, num: usize) -> &dyn ImageAccess { |
| assert_eq!(num, 0); |
| &self.destination |
| } |
| |
| fn image_name(&self, num: usize) -> Cow<'static, str> { |
| assert_eq!(num, 0); |
| "destination".into() |
| } |
| } |
| |
| self.append_command( |
| Cmd { |
| source, |
| destination, |
| destination_layout, |
| regions: Mutex::new(Some(regions)), |
| }, |
| &[ |
| ( |
| KeyTy::Buffer, |
| Some(( |
| PipelineMemoryAccess { |
| stages: PipelineStages { |
| transfer: true, |
| ..PipelineStages::none() |
| }, |
| access: AccessFlags { |
| transfer_read: true, |
| ..AccessFlags::none() |
| }, |
| exclusive: false, |
| }, |
| ImageLayout::Undefined, |
| ImageLayout::Undefined, |
| ImageUninitializedSafe::Unsafe, |
| )), |
| ), |
| ( |
| KeyTy::Image, |
| Some(( |
| PipelineMemoryAccess { |
| stages: PipelineStages { |
| transfer: true, |
| ..PipelineStages::none() |
| }, |
| access: AccessFlags { |
| transfer_write: true, |
| ..AccessFlags::none() |
| }, |
| exclusive: true, |
| }, |
| destination_layout, |
| destination_layout, |
| ImageUninitializedSafe::Safe, |
| )), |
| ), |
| ], |
| )?; |
| |
| Ok(()) |
| } |
| |
| /// Calls `vkCmdCopyImageToBuffer` on the builder. |
| /// |
| /// Does nothing if the list of regions is empty, as it would be a no-op and isn't a valid |
| /// usage of the command anyway. |
| #[inline] |
| pub unsafe fn copy_image_to_buffer<S, D, R>( |
| &mut self, |
| source: S, |
| source_layout: ImageLayout, |
| destination: D, |
| regions: R, |
| ) -> Result<(), SyncCommandBufferBuilderError> |
| where |
| S: ImageAccess + Send + Sync + 'static, |
| D: BufferAccess + Send + Sync + 'static, |
| R: IntoIterator<Item = UnsafeCommandBufferBuilderBufferImageCopy> + Send + Sync + 'static, |
| { |
| struct Cmd<S, D, R> { |
| source: S, |
| source_layout: ImageLayout, |
| destination: D, |
| regions: Mutex<Option<R>>, |
| } |
| |
| impl<S, D, R> Command for Cmd<S, D, R> |
| where |
| S: ImageAccess + Send + Sync + 'static, |
| D: BufferAccess + Send + Sync + 'static, |
| R: IntoIterator<Item = UnsafeCommandBufferBuilderBufferImageCopy>, |
| { |
| fn name(&self) -> &'static str { |
| "vkCmdCopyImageToBuffer" |
| } |
| |
| unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) { |
| out.copy_image_to_buffer( |
| &self.source, |
| self.source_layout, |
| &self.destination, |
| self.regions.lock().unwrap().take().unwrap(), |
| ); |
| } |
| |
| fn buffer(&self, num: usize) -> &dyn BufferAccess { |
| assert_eq!(num, 0); |
| &self.destination |
| } |
| |
| fn buffer_name(&self, num: usize) -> Cow<'static, str> { |
| assert_eq!(num, 0); |
| "destination".into() |
| } |
| |
| fn image(&self, num: usize) -> &dyn ImageAccess { |
| assert_eq!(num, 0); |
| &self.source |
| } |
| |
| fn image_name(&self, num: usize) -> Cow<'static, str> { |
| assert_eq!(num, 0); |
| "source".into() |
| } |
| } |
| |
| self.append_command( |
| Cmd { |
| source, |
| destination, |
| source_layout, |
| regions: Mutex::new(Some(regions)), |
| }, |
| &[ |
| ( |
| KeyTy::Image, |
| Some(( |
| PipelineMemoryAccess { |
| stages: PipelineStages { |
| transfer: true, |
| ..PipelineStages::none() |
| }, |
| access: AccessFlags { |
| transfer_read: true, |
| ..AccessFlags::none() |
| }, |
| exclusive: false, |
| }, |
| source_layout, |
| source_layout, |
| ImageUninitializedSafe::Unsafe, |
| )), |
| ), |
| ( |
| KeyTy::Buffer, |
| Some(( |
| PipelineMemoryAccess { |
| stages: PipelineStages { |
| transfer: true, |
| ..PipelineStages::none() |
| }, |
| access: AccessFlags { |
| transfer_write: true, |
| ..AccessFlags::none() |
| }, |
| exclusive: true, |
| }, |
| ImageLayout::Undefined, |
| ImageLayout::Undefined, |
| ImageUninitializedSafe::Unsafe, |
| )), |
| ), |
| ], |
| )?; |
| |
| Ok(()) |
| } |
| |
| /// Calls `vkCmdCopyQueryPoolResults` on the builder. |
| /// |
| /// # Safety |
| /// `stride` must be at least the number of bytes that will be written by each query. |
| pub unsafe fn copy_query_pool_results<D, T>( |
| &mut self, |
| query_pool: Arc<QueryPool>, |
| queries: Range<u32>, |
| destination: D, |
| stride: DeviceSize, |
| flags: QueryResultFlags, |
| ) -> Result<(), SyncCommandBufferBuilderError> |
| where |
| D: BufferAccess + TypedBufferAccess<Content = [T]> + Send + Sync + 'static, |
| T: QueryResultElement, |
| { |
| struct Cmd<D> { |
| query_pool: Arc<QueryPool>, |
| queries: Range<u32>, |
| destination: D, |
| stride: DeviceSize, |
| flags: QueryResultFlags, |
| } |
| |
| impl<D, T> Command for Cmd<D> |
| where |
| D: BufferAccess + TypedBufferAccess<Content = [T]> + Send + Sync + 'static, |
| T: QueryResultElement, |
| { |
| fn name(&self) -> &'static str { |
| "vkCmdCopyQueryPoolResults" |
| } |
| |
| unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) { |
| out.copy_query_pool_results( |
| self.query_pool.queries_range(self.queries.clone()).unwrap(), |
| &self.destination, |
| self.stride, |
| self.flags, |
| ); |
| } |
| |
| fn buffer(&self, num: usize) -> &dyn BufferAccess { |
| assert_eq!(num, 0); |
| &self.destination |
| } |
| |
| fn buffer_name(&self, num: usize) -> Cow<'static, str> { |
| assert_eq!(num, 0); |
| "destination".into() |
| } |
| } |
| |
| self.append_command( |
| Cmd { |
| query_pool, |
| queries, |
| destination, |
| stride, |
| flags, |
| }, |
| &[( |
| KeyTy::Buffer, |
| Some(( |
| PipelineMemoryAccess { |
| stages: PipelineStages { |
| transfer: true, |
| ..PipelineStages::none() |
| }, |
| access: AccessFlags { |
| transfer_write: true, |
| ..AccessFlags::none() |
| }, |
| exclusive: true, |
| }, |
| ImageLayout::Undefined, |
| ImageLayout::Undefined, |
| ImageUninitializedSafe::Unsafe, |
| )), |
| )], |
| )?; |
| |
| Ok(()) |
| } |
| |
| /// Calls `vkCmdBeginDebugUtilsLabelEXT` on the builder. |
| /// |
| /// # Safety |
| /// The command pool that this command buffer was allocated from must support graphics or |
| /// compute operations |
| #[inline] |
| pub unsafe fn debug_marker_begin(&mut self, name: &'static CStr, color: [f32; 4]) { |
| struct Cmd { |
| name: &'static CStr, |
| color: [f32; 4], |
| } |
| |
| impl Command for Cmd { |
| fn name(&self) -> &'static str { |
| "vkCmdBeginDebugUtilsLabelEXT" |
| } |
| |
| unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) { |
| out.debug_marker_begin(self.name, self.color); |
| } |
| } |
| |
| self.append_command(Cmd { name, color }, &[]).unwrap(); |
| } |
| |
| /// Calls `vkCmdEndDebugUtilsLabelEXT` on the builder. |
| /// |
| /// # Safety |
| /// - The command pool that this command buffer was allocated from must support graphics or |
| /// compute operations |
| /// - There must be an outstanding `debug_marker_begin` command prior to the |
| /// `debug_marker_end` on the queue. |
| #[inline] |
| pub unsafe fn debug_marker_end(&mut self) { |
| struct Cmd {} |
| |
| impl Command for Cmd { |
| fn name(&self) -> &'static str { |
| "vkCmdEndDebugUtilsLabelEXT" |
| } |
| |
| unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) { |
| out.debug_marker_end(); |
| } |
| } |
| |
| self.append_command(Cmd {}, &[]).unwrap(); |
| } |
| |
| /// Calls `vkCmdInsertDebugUtilsLabelEXT` on the builder. |
| /// |
| /// # Safety |
| /// The command pool that this command buffer was allocated from must support graphics or |
| /// compute operations |
| #[inline] |
| pub unsafe fn debug_marker_insert(&mut self, name: &'static CStr, color: [f32; 4]) { |
| struct Cmd { |
| name: &'static CStr, |
| color: [f32; 4], |
| } |
| |
| impl Command for Cmd { |
| fn name(&self) -> &'static str { |
| "vkCmdInsertDebugUtilsLabelEXT" |
| } |
| |
| unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) { |
| out.debug_marker_insert(self.name, self.color); |
| } |
| } |
| |
| self.append_command(Cmd { name, color }, &[]).unwrap(); |
| } |
| |
| /// Calls `vkCmdDispatch` on the builder. |
| #[inline] |
| pub unsafe fn dispatch(&mut self, group_counts: [u32; 3]) { |
| struct Cmd { |
| group_counts: [u32; 3], |
| descriptor_sets: SmallVec<[Arc<dyn Command + Send + Sync>; 12]>, |
| } |
| |
| impl Command for Cmd { |
| fn name(&self) -> &'static str { |
| "vkCmdDispatch" |
| } |
| |
| unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) { |
| out.dispatch(self.group_counts); |
| } |
| |
| fn buffer(&self, mut num: usize) -> &dyn BufferAccess { |
| for set in self |
| .descriptor_sets |
| .iter() |
| .enumerate() |
| .map(|(set_num, cmd)| cmd.bound_descriptor_set(set_num as u32).0) |
| { |
| if let Some(buf) = set.buffer(num) { |
| return buf.0; |
| } |
| num -= set.num_buffers(); |
| } |
| panic!() |
| } |
| |
| fn buffer_name(&self, mut num: usize) -> Cow<'static, str> { |
| for (set_num, set) in self |
| .descriptor_sets |
| .iter() |
| .enumerate() |
| .map(|(set_num, cmd)| (set_num, cmd.bound_descriptor_set(set_num as u32).0)) |
| { |
| if let Some(buf) = set.buffer(num) { |
| return format!("Buffer bound to set {} descriptor {}", set_num, buf.1) |
| .into(); |
| } |
| num -= set.num_buffers(); |
| } |
| panic!() |
| } |
| |
| fn image(&self, mut num: usize) -> &dyn ImageAccess { |
| for set in self |
| .descriptor_sets |
| .iter() |
| .enumerate() |
| .map(|(set_num, cmd)| cmd.bound_descriptor_set(set_num as u32).0) |
| { |
| if let Some(img) = set.image(num) { |
| return img.0.image(); |
| } |
| num -= set.num_images(); |
| } |
| panic!() |
| } |
| |
| fn image_name(&self, mut num: usize) -> Cow<'static, str> { |
| for (set_num, set) in self |
| .descriptor_sets |
| .iter() |
| .enumerate() |
| .map(|(set_num, cmd)| (set_num, cmd.bound_descriptor_set(set_num as u32).0)) |
| { |
| if let Some(img) = set.image(num) { |
| return format!("Image bound to set {} descriptor {}", set_num, img.1) |
| .into(); |
| } |
| num -= set.num_images(); |
| } |
| panic!() |
| } |
| } |
| |
| let pipeline = self |
| .bindings |
| .pipeline_compute |
| .as_ref() |
| .unwrap() |
| .bound_pipeline_compute(); |
| |
| let mut resources = Vec::new(); |
| let descriptor_sets = self.add_descriptor_set_resources( |
| &mut resources, |
| pipeline.layout(), |
| PipelineBindPoint::Compute, |
| ); |
| |
| self.append_command( |
| Cmd { |
| group_counts, |
| descriptor_sets, |
| }, |
| &resources, |
| ) |
| .unwrap(); |
| } |
| |
| /// Calls `vkCmdDispatchIndirect` on the builder. |
| #[inline] |
| pub unsafe fn dispatch_indirect<B>( |
| &mut self, |
| indirect_buffer: B, |
| ) -> Result<(), SyncCommandBufferBuilderError> |
| where |
| B: BufferAccess + Send + Sync + 'static, |
| { |
| struct Cmd<B> { |
| descriptor_sets: SmallVec<[Arc<dyn Command + Send + Sync>; 12]>, |
| indirect_buffer: B, |
| } |
| |
| impl<B> Command for Cmd<B> |
| where |
| B: BufferAccess + Send + Sync + 'static, |
| { |
| fn name(&self) -> &'static str { |
| "vkCmdDispatchIndirect" |
| } |
| |
| unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) { |
| out.dispatch_indirect(&self.indirect_buffer); |
| } |
| |
| fn buffer(&self, mut num: usize) -> &dyn BufferAccess { |
| for set in self |
| .descriptor_sets |
| .iter() |
| .enumerate() |
| .map(|(set_num, cmd)| cmd.bound_descriptor_set(set_num as u32).0) |
| { |
| if let Some(buf) = set.buffer(num) { |
| return buf.0; |
| } |
| num -= set.num_buffers(); |
| } |
| if num == 0 { |
| return &self.indirect_buffer; |
| } |
| panic!() |
| } |
| |
| fn buffer_name(&self, mut num: usize) -> Cow<'static, str> { |
| for (set_num, set) in self |
| .descriptor_sets |
| .iter() |
| .enumerate() |
| .map(|(set_num, cmd)| (set_num, cmd.bound_descriptor_set(set_num as u32).0)) |
| { |
| if let Some(buf) = set.buffer(num) { |
| return format!("Buffer bound to set {} descriptor {}", set_num, buf.1) |
| .into(); |
| } |
| num -= set.num_buffers(); |
| } |
| if num == 0 { |
| return "indirect buffer".into(); |
| } |
| panic!() |
| } |
| |
| fn image(&self, mut num: usize) -> &dyn ImageAccess { |
| for set in self |
| .descriptor_sets |
| .iter() |
| .enumerate() |
| .map(|(set_num, cmd)| cmd.bound_descriptor_set(set_num as u32).0) |
| { |
| if let Some(img) = set.image(num) { |
| return img.0.image(); |
| } |
| num -= set.num_images(); |
| } |
| panic!() |
| } |
| |
| fn image_name(&self, mut num: usize) -> Cow<'static, str> { |
| for (set_num, set) in self |
| .descriptor_sets |
| .iter() |
| .enumerate() |
| .map(|(set_num, cmd)| (set_num, cmd.bound_descriptor_set(set_num as u32).0)) |
| { |
| if let Some(img) = set.image(num) { |
| return format!("Image bound to set {} descriptor {}", set_num, img.1) |
| .into(); |
| } |
| num -= set.num_images(); |
| } |
| panic!() |
| } |
| } |
| |
| let pipeline = self |
| .bindings |
| .pipeline_compute |
| .as_ref() |
| .unwrap() |
| .bound_pipeline_compute(); |
| |
| let mut resources = Vec::new(); |
| let descriptor_sets = self.add_descriptor_set_resources( |
| &mut resources, |
| pipeline.layout(), |
| PipelineBindPoint::Compute, |
| ); |
| self.add_indirect_buffer_resources(&mut resources); |
| |
| self.append_command( |
| Cmd { |
| descriptor_sets, |
| indirect_buffer, |
| }, |
| &resources, |
| )?; |
| |
| Ok(()) |
| } |
| |
| /// Calls `vkCmdDraw` on the builder. |
| #[inline] |
| pub unsafe fn draw( |
| &mut self, |
| vertex_count: u32, |
| instance_count: u32, |
| first_vertex: u32, |
| first_instance: u32, |
| ) { |
| struct Cmd { |
| descriptor_sets: SmallVec<[Arc<dyn Command + Send + Sync>; 12]>, |
| vertex_buffers: SmallVec<[(u32, Arc<dyn Command + Send + Sync>); 4]>, |
| vertex_count: u32, |
| instance_count: u32, |
| first_vertex: u32, |
| first_instance: u32, |
| } |
| |
| impl Command for Cmd { |
| fn name(&self) -> &'static str { |
| "vkCmdDraw" |
| } |
| |
| unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) { |
| out.draw( |
| self.vertex_count, |
| self.instance_count, |
| self.first_vertex, |
| self.first_instance, |
| ); |
| } |
| |
| fn buffer(&self, mut num: usize) -> &dyn BufferAccess { |
| for set in self |
| .descriptor_sets |
| .iter() |
| .enumerate() |
| .map(|(set_num, cmd)| cmd.bound_descriptor_set(set_num as u32).0) |
| { |
| if let Some(buf) = set.buffer(num) { |
| return buf.0; |
| } |
| num -= set.num_buffers(); |
| } |
| |
| for buffer in self |
| .vertex_buffers |
| .iter() |
| .map(|(binding_num, cmd)| cmd.bound_vertex_buffer(*binding_num)) |
| { |
| if num == 0 { |
| return buffer; |
| } |
| num -= 1; |
| } |
| |
| panic!() |
| } |
| |
| fn buffer_name(&self, mut num: usize) -> Cow<'static, str> { |
| for (set_num, set) in self |
| .descriptor_sets |
| .iter() |
| .enumerate() |
| .map(|(set_num, cmd)| (set_num, cmd.bound_descriptor_set(set_num as u32).0)) |
| { |
| if let Some(buf) = set.buffer(num) { |
| return format!("Buffer bound to set {} descriptor {}", set_num, buf.1) |
| .into(); |
| } |
| num -= set.num_buffers(); |
| } |
| |
| for binding_num in self |
| .vertex_buffers |
| .iter() |
| .map(|(binding_num, _)| *binding_num) |
| { |
| if num == 0 { |
| return format!("Vertex buffer binding {}", binding_num).into(); |
| } |
| num -= 1; |
| } |
| |
| panic!() |
| } |
| |
| fn image(&self, mut num: usize) -> &dyn ImageAccess { |
| for set in self |
| .descriptor_sets |
| .iter() |
| .enumerate() |
| .map(|(set_num, cmd)| cmd.bound_descriptor_set(set_num as u32).0) |
| { |
| if let Some(img) = set.image(num) { |
| return img.0.image(); |
| } |
| num -= set.num_images(); |
| } |
| panic!() |
| } |
| |
| fn image_name(&self, mut num: usize) -> Cow<'static, str> { |
| for (set_num, set) in self |
| .descriptor_sets |
| .iter() |
| .enumerate() |
| .map(|(set_num, cmd)| (set_num, cmd.bound_descriptor_set(set_num as u32).0)) |
| { |
| if let Some(img) = set.image(num) { |
| return format!("Image bound to set {} descriptor {}", set_num, img.1) |
| .into(); |
| } |
| num -= set.num_images(); |
| } |
| panic!() |
| } |
| } |
| |
| let pipeline = self |
| .bindings |
| .pipeline_graphics |
| .as_ref() |
| .unwrap() |
| .bound_pipeline_graphics(); |
| |
| let mut resources = Vec::new(); |
| let descriptor_sets = self.add_descriptor_set_resources( |
| &mut resources, |
| pipeline.layout(), |
| PipelineBindPoint::Graphics, |
| ); |
| let vertex_buffers = |
| self.add_vertex_buffer_resources(&mut resources, pipeline.vertex_input()); |
| |
| self.append_command( |
| Cmd { |
| descriptor_sets, |
| vertex_buffers, |
| vertex_count, |
| instance_count, |
| first_vertex, |
| first_instance, |
| }, |
| &resources, |
| ) |
| .unwrap(); |
| } |
| |
| /// Calls `vkCmdDrawIndexed` on the builder. |
| #[inline] |
| pub unsafe fn draw_indexed( |
| &mut self, |
| index_count: u32, |
| instance_count: u32, |
| first_index: u32, |
| vertex_offset: i32, |
| first_instance: u32, |
| ) { |
| struct Cmd { |
| descriptor_sets: SmallVec<[Arc<dyn Command + Send + Sync>; 12]>, |
| vertex_buffers: SmallVec<[(u32, Arc<dyn Command + Send + Sync>); 4]>, |
| index_buffer: Arc<dyn Command + Send + Sync>, |
| index_count: u32, |
| instance_count: u32, |
| first_index: u32, |
| vertex_offset: i32, |
| first_instance: u32, |
| } |
| |
| impl Command for Cmd { |
| fn name(&self) -> &'static str { |
| "vkCmdDrawIndexed" |
| } |
| |
| unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) { |
| out.draw_indexed( |
| self.index_count, |
| self.instance_count, |
| self.first_index, |
| self.vertex_offset, |
| self.first_instance, |
| ); |
| } |
| |
| fn buffer(&self, mut num: usize) -> &dyn BufferAccess { |
| for set in self |
| .descriptor_sets |
| .iter() |
| .enumerate() |
| .map(|(set_num, cmd)| cmd.bound_descriptor_set(set_num as u32).0) |
| { |
| if let Some(buf) = set.buffer(num) { |
| return buf.0; |
| } |
| num -= set.num_buffers(); |
| } |
| |
| for buffer in self |
| .vertex_buffers |
| .iter() |
| .map(|(binding_num, cmd)| cmd.bound_vertex_buffer(*binding_num)) |
| { |
| if num == 0 { |
| return buffer; |
| } |
| num -= 1; |
| } |
| |
| if num == 0 { |
| return self.index_buffer.bound_index_buffer(); |
| } |
| |
| panic!() |
| } |
| |
| fn buffer_name(&self, mut num: usize) -> Cow<'static, str> { |
| for (set_num, set) in self |
| .descriptor_sets |
| .iter() |
| .enumerate() |
| .map(|(set_num, cmd)| (set_num, cmd.bound_descriptor_set(set_num as u32).0)) |
| { |
| if let Some(buf) = set.buffer(num) { |
| return format!("Buffer bound to set {} descriptor {}", set_num, buf.1) |
| .into(); |
| } |
| num -= set.num_buffers(); |
| } |
| |
| for binding_num in self |
| .vertex_buffers |
| .iter() |
| .map(|(binding_num, _)| *binding_num) |
| { |
| if num == 0 { |
| return format!("Vertex buffer binding {}", binding_num).into(); |
| } |
| num -= 1; |
| } |
| |
| if num == 0 { |
| return "index buffer".into(); |
| } |
| |
| panic!() |
| } |
| |
| fn image(&self, mut num: usize) -> &dyn ImageAccess { |
| for set in self |
| .descriptor_sets |
| .iter() |
| .enumerate() |
| .map(|(set_num, cmd)| cmd.bound_descriptor_set(set_num as u32).0) |
| { |
| if let Some(img) = set.image(num) { |
| return img.0.image(); |
| } |
| num -= set.num_images(); |
| } |
| panic!() |
| } |
| |
| fn image_name(&self, mut num: usize) -> Cow<'static, str> { |
| for (set_num, set) in self |
| .descriptor_sets |
| .iter() |
| .enumerate() |
| .map(|(set_num, cmd)| (set_num, cmd.bound_descriptor_set(set_num as u32).0)) |
| { |
| if let Some(img) = set.image(num) { |
| return format!("Image bound to set {} descriptor {}", set_num, img.1) |
| .into(); |
| } |
| num -= set.num_images(); |
| } |
| panic!() |
| } |
| } |
| |
| let pipeline = self |
| .bindings |
| .pipeline_graphics |
| .as_ref() |
| .unwrap() |
| .bound_pipeline_graphics(); |
| |
| let mut resources = Vec::new(); |
| let descriptor_sets = self.add_descriptor_set_resources( |
| &mut resources, |
| pipeline.layout(), |
| PipelineBindPoint::Graphics, |
| ); |
| let vertex_buffers = |
| self.add_vertex_buffer_resources(&mut resources, pipeline.vertex_input()); |
| let index_buffer = self.add_index_buffer_resources(&mut resources); |
| |
| self.append_command( |
| Cmd { |
| descriptor_sets, |
| vertex_buffers, |
| index_buffer, |
| index_count, |
| instance_count, |
| first_index, |
| vertex_offset, |
| first_instance, |
| }, |
| &resources, |
| ) |
| .unwrap(); |
| } |
| |
| /// Calls `vkCmdDrawIndirect` on the builder. |
| #[inline] |
| pub unsafe fn draw_indirect<B>( |
| &mut self, |
| indirect_buffer: B, |
| draw_count: u32, |
| stride: u32, |
| ) -> Result<(), SyncCommandBufferBuilderError> |
| where |
| B: BufferAccess + Send + Sync + 'static, |
| { |
| struct Cmd<B> { |
| descriptor_sets: SmallVec<[Arc<dyn Command + Send + Sync>; 12]>, |
| vertex_buffers: SmallVec<[(u32, Arc<dyn Command + Send + Sync>); 4]>, |
| indirect_buffer: B, |
| draw_count: u32, |
| stride: u32, |
| } |
| |
| impl<B> Command for Cmd<B> |
| where |
| B: BufferAccess + Send + Sync + 'static, |
| { |
| fn name(&self) -> &'static str { |
| "vkCmdDrawIndirect" |
| } |
| |
| unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) { |
| out.draw_indirect(&self.indirect_buffer, self.draw_count, self.stride); |
| } |
| |
| fn buffer(&self, mut num: usize) -> &dyn BufferAccess { |
| for set in self |
| .descriptor_sets |
| .iter() |
| .enumerate() |
| .map(|(set_num, cmd)| cmd.bound_descriptor_set(set_num as u32).0) |
| { |
| if let Some(buf) = set.buffer(num) { |
| return buf.0; |
| } |
| num -= set.num_buffers(); |
| } |
| |
| for buffer in self |
| .vertex_buffers |
| .iter() |
| .map(|(binding_num, cmd)| cmd.bound_vertex_buffer(*binding_num)) |
| { |
| if num == 0 { |
| return buffer; |
| } |
| num -= 1; |
| } |
| |
| if num == 0 { |
| return &self.indirect_buffer; |
| } |
| |
| panic!() |
| } |
| |
| fn buffer_name(&self, mut num: usize) -> Cow<'static, str> { |
| for (set_num, set) in self |
| .descriptor_sets |
| .iter() |
| .enumerate() |
| .map(|(set_num, cmd)| (set_num, cmd.bound_descriptor_set(set_num as u32).0)) |
| { |
| if let Some(buf) = set.buffer(num) { |
| return format!("Buffer bound to set {} descriptor {}", set_num, buf.1) |
| .into(); |
| } |
| num -= set.num_buffers(); |
| } |
| |
| for binding_num in self |
| .vertex_buffers |
| .iter() |
| .map(|(binding_num, _)| *binding_num) |
| { |
| if num == 0 { |
| return format!("Vertex buffer binding {}", binding_num).into(); |
| } |
| num -= 1; |
| } |
| |
| if num == 0 { |
| return "indirect buffer".into(); |
| } |
| |
| panic!() |
| } |
| |
| fn image(&self, mut num: usize) -> &dyn ImageAccess { |
| for set in self |
| .descriptor_sets |
| .iter() |
| .enumerate() |
| .map(|(set_num, cmd)| cmd.bound_descriptor_set(set_num as u32).0) |
| { |
| if let Some(img) = set.image(num) { |
| return img.0.image(); |
| } |
| num -= set.num_images(); |
| } |
| panic!() |
| } |
| |
| fn image_name(&self, mut num: usize) -> Cow<'static, str> { |
| for (set_num, set) in self |
| .descriptor_sets |
| .iter() |
| .enumerate() |
| .map(|(set_num, cmd)| (set_num, cmd.bound_descriptor_set(set_num as u32).0)) |
| { |
| if let Some(img) = set.image(num) { |
| return format!("Image bound to set {} descriptor {}", set_num, img.1) |
| .into(); |
| } |
| num -= set.num_images(); |
| } |
| panic!() |
| } |
| } |
| |
| let pipeline = self |
| .bindings |
| .pipeline_graphics |
| .as_ref() |
| .unwrap() |
| .bound_pipeline_graphics(); |
| |
| let mut resources = Vec::new(); |
| let descriptor_sets = self.add_descriptor_set_resources( |
| &mut resources, |
| pipeline.layout(), |
| PipelineBindPoint::Graphics, |
| ); |
| let vertex_buffers = |
| self.add_vertex_buffer_resources(&mut resources, pipeline.vertex_input()); |
| self.add_indirect_buffer_resources(&mut resources); |
| |
| self.append_command( |
| Cmd { |
| descriptor_sets, |
| vertex_buffers, |
| indirect_buffer, |
| draw_count, |
| stride, |
| }, |
| &resources, |
| )?; |
| |
| Ok(()) |
| } |
| |
| /// Calls `vkCmdDrawIndexedIndirect` on the builder. |
| #[inline] |
| pub unsafe fn draw_indexed_indirect<B>( |
| &mut self, |
| indirect_buffer: B, |
| draw_count: u32, |
| stride: u32, |
| ) -> Result<(), SyncCommandBufferBuilderError> |
| where |
| B: BufferAccess + Send + Sync + 'static, |
| { |
| struct Cmd<B> { |
| descriptor_sets: SmallVec<[Arc<dyn Command + Send + Sync>; 12]>, |
| vertex_buffers: SmallVec<[(u32, Arc<dyn Command + Send + Sync>); 4]>, |
| index_buffer: Arc<dyn Command + Send + Sync>, |
| indirect_buffer: B, |
| draw_count: u32, |
| stride: u32, |
| } |
| |
| impl<B> Command for Cmd<B> |
| where |
| B: BufferAccess + Send + Sync + 'static, |
| { |
| fn name(&self) -> &'static str { |
| "vkCmdDrawIndexedIndirect" |
| } |
| |
| unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) { |
| out.draw_indexed_indirect(&self.indirect_buffer, self.draw_count, self.stride); |
| } |
| |
| fn buffer(&self, mut num: usize) -> &dyn BufferAccess { |
| for set in self |
| .descriptor_sets |
| .iter() |
| .enumerate() |
| .map(|(set_num, cmd)| cmd.bound_descriptor_set(set_num as u32).0) |
| { |
| if let Some(buf) = set.buffer(num) { |
| return buf.0; |
| } |
| num -= set.num_buffers(); |
| } |
| |
| for buffer in self |
| .vertex_buffers |
| .iter() |
| .map(|(binding_num, cmd)| cmd.bound_vertex_buffer(*binding_num)) |
| { |
| if num == 0 { |
| return buffer; |
| } |
| num -= 1; |
| } |
| |
| if num == 0 { |
| return self.index_buffer.bound_index_buffer(); |
| } else if num == 1 { |
| return &self.indirect_buffer; |
| } |
| |
| panic!() |
| } |
| |
| fn buffer_name(&self, mut num: usize) -> Cow<'static, str> { |
| for (set_num, set) in self |
| .descriptor_sets |
| .iter() |
| .enumerate() |
| .map(|(set_num, cmd)| (set_num, cmd.bound_descriptor_set(set_num as u32).0)) |
| { |
| if let Some(buf) = set.buffer(num) { |
| return format!("Buffer bound to set {} descriptor {}", set_num, buf.1) |
| .into(); |
| } |
| num -= set.num_buffers(); |
| } |
| |
| for binding_num in self |
| .vertex_buffers |
| .iter() |
| .map(|(binding_num, _)| *binding_num) |
| { |
| if num == 0 { |
| return format!("Vertex buffer binding {}", binding_num).into(); |
| } |
| num -= 1; |
| } |
| |
| if num == 0 { |
| return "index buffer".into(); |
| } else if num == 1 { |
| return "indirect buffer".into(); |
| } |
| |
| panic!() |
| } |
| |
| fn image(&self, mut num: usize) -> &dyn ImageAccess { |
| for set in self |
| .descriptor_sets |
| .iter() |
| .enumerate() |
| .map(|(set_num, cmd)| cmd.bound_descriptor_set(set_num as u32).0) |
| { |
| if let Some(img) = set.image(num) { |
| return img.0.image(); |
| } |
| num -= set.num_images(); |
| } |
| panic!() |
| } |
| |
| fn image_name(&self, mut num: usize) -> Cow<'static, str> { |
| for (set_num, set) in self |
| .descriptor_sets |
| .iter() |
| .enumerate() |
| .map(|(set_num, cmd)| (set_num, cmd.bound_descriptor_set(set_num as u32).0)) |
| { |
| if let Some(img) = set.image(num) { |
| return format!("Image bound to set {} descriptor {}", set_num, img.1) |
| .into(); |
| } |
| num -= set.num_images(); |
| } |
| panic!() |
| } |
| } |
| |
| let pipeline = self |
| .bindings |
| .pipeline_graphics |
| .as_ref() |
| .unwrap() |
| .bound_pipeline_graphics(); |
| |
| let mut resources = Vec::new(); |
| let descriptor_sets = self.add_descriptor_set_resources( |
| &mut resources, |
| pipeline.layout(), |
| PipelineBindPoint::Graphics, |
| ); |
| let vertex_buffers = |
| self.add_vertex_buffer_resources(&mut resources, pipeline.vertex_input()); |
| let index_buffer = self.add_index_buffer_resources(&mut resources); |
| self.add_indirect_buffer_resources(&mut resources); |
| |
| self.append_command( |
| Cmd { |
| descriptor_sets, |
| vertex_buffers, |
| index_buffer, |
| indirect_buffer, |
| draw_count, |
| stride, |
| }, |
| &resources, |
| )?; |
| |
| Ok(()) |
| } |
| |
| /// Calls `vkCmdEndQuery` on the builder. |
| #[inline] |
| pub unsafe fn end_query(&mut self, query_pool: Arc<QueryPool>, query: u32) { |
| struct Cmd { |
| query_pool: Arc<QueryPool>, |
| query: u32, |
| } |
| |
| impl Command for Cmd { |
| fn name(&self) -> &'static str { |
| "vkCmdEndQuery" |
| } |
| |
| unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) { |
| out.end_query(self.query_pool.query(self.query).unwrap()); |
| } |
| } |
| |
| self.append_command(Cmd { query_pool, query }, &[]).unwrap(); |
| } |
| |
| /// Calls `vkCmdEndRenderPass` on the builder. |
| #[inline] |
| pub unsafe fn end_render_pass(&mut self) { |
| struct Cmd; |
| |
| impl Command for Cmd { |
| fn name(&self) -> &'static str { |
| "vkCmdEndRenderPass" |
| } |
| |
| unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) { |
| out.end_render_pass(); |
| } |
| } |
| |
| self.append_command(Cmd, &[]).unwrap(); |
| debug_assert!(self.latest_render_pass_enter.is_some()); |
| self.latest_render_pass_enter = None; |
| } |
| |
| /// Starts the process of executing secondary command buffers. Returns an intermediate struct |
| /// which can be used to add the command buffers. |
| #[inline] |
| pub unsafe fn execute_commands(&mut self) -> SyncCommandBufferBuilderExecuteCommands { |
| SyncCommandBufferBuilderExecuteCommands { |
| builder: self, |
| inner: Vec::new(), |
| } |
| } |
| |
| /// Calls `vkCmdFillBuffer` on the builder. |
| #[inline] |
| pub unsafe fn fill_buffer<B>(&mut self, buffer: B, data: u32) |
| where |
| B: BufferAccess + Send + Sync + 'static, |
| { |
| struct Cmd<B> { |
| buffer: B, |
| data: u32, |
| } |
| |
| impl<B> Command for Cmd<B> |
| where |
| B: BufferAccess + Send + Sync + 'static, |
| { |
| fn name(&self) -> &'static str { |
| "vkCmdFillBuffer" |
| } |
| |
| unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) { |
| out.fill_buffer(&self.buffer, self.data); |
| } |
| |
| fn buffer(&self, num: usize) -> &dyn BufferAccess { |
| assert_eq!(num, 0); |
| &self.buffer |
| } |
| |
| fn buffer_name(&self, _: usize) -> Cow<'static, str> { |
| "destination".into() |
| } |
| } |
| |
| self.append_command( |
| Cmd { buffer, data }, |
| &[( |
| KeyTy::Buffer, |
| Some(( |
| PipelineMemoryAccess { |
| stages: PipelineStages { |
| transfer: true, |
| ..PipelineStages::none() |
| }, |
| access: AccessFlags { |
| transfer_write: true, |
| ..AccessFlags::none() |
| }, |
| exclusive: true, |
| }, |
| ImageLayout::Undefined, |
| ImageLayout::Undefined, |
| ImageUninitializedSafe::Unsafe, |
| )), |
| )], |
| ) |
| .unwrap(); |
| } |
| |
| /// Calls `vkCmdNextSubpass` on the builder. |
| #[inline] |
| pub unsafe fn next_subpass(&mut self, subpass_contents: SubpassContents) { |
| struct Cmd { |
| subpass_contents: SubpassContents, |
| } |
| |
| impl Command for Cmd { |
| fn name(&self) -> &'static str { |
| "vkCmdNextSubpass" |
| } |
| |
| unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) { |
| out.next_subpass(self.subpass_contents); |
| } |
| } |
| |
| self.append_command(Cmd { subpass_contents }, &[]).unwrap(); |
| } |
| |
| /// Calls `vkCmdPushConstants` on the builder. |
| #[inline] |
| 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 { |
| "vkCmdPushConstants" |
| } |
| |
| unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) { |
| out.push_constants::<[u8]>( |
| &self.pipeline_layout, |
| self.stages, |
| self.offset, |
| self.size, |
| &self.data, |
| ); |
| } |
| } |
| |
| debug_assert!(mem::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.append_command( |
| Cmd { |
| pipeline_layout, |
| stages, |
| offset, |
| size, |
| data: out.into(), |
| }, |
| &[], |
| ) |
| .unwrap(); |
| } |
| |
| /// Calls `vkCmdResetEvent` on the builder. |
| #[inline] |
| pub unsafe fn reset_event(&mut self, event: Arc<Event>, stages: PipelineStages) { |
| struct Cmd { |
| event: Arc<Event>, |
| stages: PipelineStages, |
| } |
| |
| impl Command for Cmd { |
| fn name(&self) -> &'static str { |
| "vkCmdResetEvent" |
| } |
| |
| unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) { |
| out.reset_event(&self.event, self.stages); |
| } |
| } |
| |
| self.append_command(Cmd { event, stages }, &[]).unwrap(); |
| } |
| |
| /// Calls `vkCmdResetQueryPool` on the builder. |
| #[inline] |
| pub unsafe fn reset_query_pool(&mut self, query_pool: Arc<QueryPool>, queries: Range<u32>) { |
| struct Cmd { |
| query_pool: Arc<QueryPool>, |
| queries: Range<u32>, |
| } |
| |
| impl Command for Cmd { |
| fn name(&self) -> &'static str { |
| "vkCmdResetQueryPool" |
| } |
| |
| unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) { |
| out.reset_query_pool(self.query_pool.queries_range(self.queries.clone()).unwrap()); |
| } |
| } |
| |
| self.append_command( |
| Cmd { |
| query_pool, |
| queries, |
| }, |
| &[], |
| ) |
| .unwrap(); |
| } |
| |
| /// Calls `vkCmdSetBlendConstants` on the builder. |
| #[inline] |
| pub unsafe fn set_blend_constants(&mut self, constants: [f32; 4]) { |
| struct Cmd { |
| constants: [f32; 4], |
| } |
| |
| impl Command for Cmd { |
| fn name(&self) -> &'static str { |
| "vkCmdSetBlendConstants" |
| } |
| |
| unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) { |
| out.set_blend_constants(self.constants); |
| } |
| } |
| |
| self.append_command(Cmd { constants }, &[]).unwrap(); |
| } |
| |
| /// Calls `vkCmdSetDepthBias` on the builder. |
| #[inline] |
| pub unsafe fn set_depth_bias(&mut self, constant_factor: f32, clamp: f32, slope_factor: f32) { |
| struct Cmd { |
| constant_factor: f32, |
| clamp: f32, |
| slope_factor: f32, |
| } |
| |
| impl Command for Cmd { |
| fn name(&self) -> &'static str { |
| "vkCmdSetDepthBias" |
| } |
| |
| unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) { |
| out.set_depth_bias(self.constant_factor, self.clamp, self.slope_factor); |
| } |
| } |
| |
| self.append_command( |
| Cmd { |
| constant_factor, |
| clamp, |
| slope_factor, |
| }, |
| &[], |
| ) |
| .unwrap(); |
| } |
| |
| /// Calls `vkCmdSetDepthBounds` on the builder. |
| #[inline] |
| pub unsafe fn set_depth_bounds(&mut self, min: f32, max: f32) { |
| struct Cmd { |
| min: f32, |
| max: f32, |
| } |
| |
| impl Command for Cmd { |
| fn name(&self) -> &'static str { |
| "vkCmdSetDepthBounds" |
| } |
| |
| unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) { |
| out.set_depth_bounds(self.min, self.max); |
| } |
| } |
| |
| self.append_command(Cmd { min, max }, &[]).unwrap(); |
| } |
| |
| /// Calls `vkCmdSetEvent` on the builder. |
| #[inline] |
| pub unsafe fn set_event(&mut self, event: Arc<Event>, stages: PipelineStages) { |
| struct Cmd { |
| event: Arc<Event>, |
| stages: PipelineStages, |
| } |
| |
| impl Command for Cmd { |
| fn name(&self) -> &'static str { |
| "vkCmdSetEvent" |
| } |
| |
| unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) { |
| out.set_event(&self.event, self.stages); |
| } |
| } |
| |
| self.append_command(Cmd { event, stages }, &[]).unwrap(); |
| } |
| |
| /// Calls `vkCmdSetLineWidth` on the builder. |
| #[inline] |
| pub unsafe fn set_line_width(&mut self, line_width: f32) { |
| struct Cmd { |
| line_width: f32, |
| } |
| |
| impl Command for Cmd { |
| fn name(&self) -> &'static str { |
| "vkCmdSetLineWidth" |
| } |
| |
| unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) { |
| out.set_line_width(self.line_width); |
| } |
| } |
| |
| self.append_command(Cmd { line_width }, &[]).unwrap(); |
| } |
| |
| /// Calls `vkCmdSetStencilCompareMask` on the builder. |
| #[inline] |
| pub unsafe fn set_stencil_compare_mask(&mut self, face_mask: StencilFaces, compare_mask: u32) { |
| struct Cmd { |
| face_mask: StencilFaces, |
| compare_mask: u32, |
| } |
| |
| impl Command for Cmd { |
| fn name(&self) -> &'static str { |
| "vkCmdSetStencilCompareMask" |
| } |
| |
| unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) { |
| out.set_stencil_compare_mask(self.face_mask, self.compare_mask); |
| } |
| } |
| |
| self.append_command( |
| Cmd { |
| face_mask, |
| compare_mask, |
| }, |
| &[], |
| ) |
| .unwrap(); |
| } |
| |
| /// Calls `vkCmdSetStencilReference` on the builder. |
| #[inline] |
| pub unsafe fn set_stencil_reference(&mut self, face_mask: StencilFaces, reference: u32) { |
| struct Cmd { |
| face_mask: StencilFaces, |
| reference: u32, |
| } |
| |
| impl Command for Cmd { |
| fn name(&self) -> &'static str { |
| "vkCmdSetStencilReference" |
| } |
| |
| unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) { |
| out.set_stencil_reference(self.face_mask, self.reference); |
| } |
| } |
| |
| self.append_command( |
| Cmd { |
| face_mask, |
| reference, |
| }, |
| &[], |
| ) |
| .unwrap(); |
| } |
| |
| /// Calls `vkCmdSetStencilWriteMask` on the builder. |
| #[inline] |
| pub unsafe fn set_stencil_write_mask(&mut self, face_mask: StencilFaces, write_mask: u32) { |
| struct Cmd { |
| face_mask: StencilFaces, |
| write_mask: u32, |
| } |
| |
| impl Command for Cmd { |
| fn name(&self) -> &'static str { |
| "vkCmdSetStencilWriteMask" |
| } |
| |
| unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) { |
| out.set_stencil_write_mask(self.face_mask, self.write_mask); |
| } |
| } |
| |
| self.append_command( |
| Cmd { |
| face_mask, |
| write_mask, |
| }, |
| &[], |
| ) |
| .unwrap(); |
| } |
| |
| /// Calls `vkCmdSetScissor` on the builder. |
| /// |
| /// If the list is empty then the command is automatically ignored. |
| #[inline] |
| pub unsafe fn set_scissor<I>(&mut self, first_scissor: u32, scissors: I) |
| where |
| I: IntoIterator<Item = Scissor> + Send + Sync + 'static, |
| { |
| struct Cmd<I> { |
| first_scissor: u32, |
| scissors: Mutex<Option<I>>, |
| } |
| |
| impl<I> Command for Cmd<I> |
| where |
| I: IntoIterator<Item = Scissor>, |
| { |
| fn name(&self) -> &'static str { |
| "vkCmdSetScissor" |
| } |
| |
| unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) { |
| out.set_scissor( |
| self.first_scissor, |
| self.scissors.lock().unwrap().take().unwrap(), |
| ); |
| } |
| } |
| |
| self.append_command( |
| Cmd { |
| first_scissor, |
| scissors: Mutex::new(Some(scissors)), |
| }, |
| &[], |
| ) |
| .unwrap(); |
| } |
| |
| /// Calls `vkCmdSetViewport` on the builder. |
| /// |
| /// If the list is empty then the command is automatically ignored. |
| #[inline] |
| pub unsafe fn set_viewport<I>(&mut self, first_viewport: u32, viewports: I) |
| where |
| I: IntoIterator<Item = Viewport> + Send + Sync + 'static, |
| { |
| struct Cmd<I> { |
| first_viewport: u32, |
| viewports: Mutex<Option<I>>, |
| } |
| |
| impl<I> Command for Cmd<I> |
| where |
| I: IntoIterator<Item = Viewport>, |
| { |
| fn name(&self) -> &'static str { |
| "vkCmdSetViewport" |
| } |
| |
| unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) { |
| out.set_viewport( |
| self.first_viewport, |
| self.viewports.lock().unwrap().take().unwrap(), |
| ); |
| } |
| } |
| |
| self.append_command( |
| Cmd { |
| first_viewport, |
| viewports: Mutex::new(Some(viewports)), |
| }, |
| &[], |
| ) |
| .unwrap(); |
| } |
| |
| /// Calls `vkCmdUpdateBuffer` on the builder. |
| #[inline] |
| pub unsafe fn update_buffer<B, D, Dd>(&mut self, buffer: B, data: Dd) |
| where |
| B: BufferAccess + Send + Sync + 'static, |
| D: ?Sized, |
| Dd: SafeDeref<Target = D> + Send + Sync + 'static, |
| { |
| struct Cmd<B, Dd> { |
| buffer: B, |
| data: Dd, |
| } |
| |
| impl<B, D, Dd> Command for Cmd<B, Dd> |
| where |
| B: BufferAccess + Send + Sync + 'static, |
| D: ?Sized, |
| Dd: SafeDeref<Target = D> + Send + Sync + 'static, |
| { |
| fn name(&self) -> &'static str { |
| "vkCmdUpdateBuffer" |
| } |
| |
| unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) { |
| out.update_buffer(&self.buffer, self.data.deref()); |
| } |
| |
| fn buffer(&self, num: usize) -> &dyn BufferAccess { |
| assert_eq!(num, 0); |
| &self.buffer |
| } |
| |
| fn buffer_name(&self, _: usize) -> Cow<'static, str> { |
| "destination".into() |
| } |
| } |
| |
| self.append_command( |
| Cmd { buffer, data }, |
| &[( |
| KeyTy::Buffer, |
| Some(( |
| PipelineMemoryAccess { |
| stages: PipelineStages { |
| transfer: true, |
| ..PipelineStages::none() |
| }, |
| access: AccessFlags { |
| transfer_write: true, |
| ..AccessFlags::none() |
| }, |
| exclusive: true, |
| }, |
| ImageLayout::Undefined, |
| ImageLayout::Undefined, |
| ImageUninitializedSafe::Unsafe, |
| )), |
| )], |
| ) |
| .unwrap(); |
| } |
| |
| /// Calls `vkCmdWriteTimestamp` on the builder. |
| #[inline] |
| pub unsafe fn write_timestamp( |
| &mut self, |
| query_pool: Arc<QueryPool>, |
| query: u32, |
| stage: PipelineStage, |
| ) { |
| struct Cmd { |
| query_pool: Arc<QueryPool>, |
| query: u32, |
| stage: PipelineStage, |
| } |
| |
| impl Command for Cmd { |
| fn name(&self) -> &'static str { |
| "vkCmdWriteTimestamp" |
| } |
| |
| unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) { |
| out.write_timestamp(self.query_pool.query(self.query).unwrap(), self.stage); |
| } |
| } |
| |
| self.append_command( |
| Cmd { |
| query_pool, |
| query, |
| stage, |
| }, |
| &[], |
| ) |
| .unwrap(); |
| } |
| |
| fn add_descriptor_set_resources( |
| &self, |
| resources: &mut Vec<( |
| KeyTy, |
| Option<( |
| PipelineMemoryAccess, |
| ImageLayout, |
| ImageLayout, |
| ImageUninitializedSafe, |
| )>, |
| )>, |
| pipeline_layout: &PipelineLayout, |
| pipeline_bind_point: PipelineBindPoint, |
| ) -> SmallVec<[Arc<dyn Command + Send + Sync>; 12]> { |
| let descriptor_sets: SmallVec<[Arc<dyn Command + Send + Sync>; 12]> = (0..pipeline_layout |
| .descriptor_set_layouts() |
| .len() |
| as u32) |
| .map(|set_num| self.bindings.descriptor_sets[&pipeline_bind_point][&set_num].clone()) |
| .collect(); |
| |
| for ds in descriptor_sets |
| .iter() |
| .enumerate() |
| .map(|(set_num, cmd)| cmd.bound_descriptor_set(set_num as u32).0) |
| { |
| for buf_num in 0..ds.num_buffers() { |
| let desc = ds |
| .layout() |
| .descriptor(ds.buffer(buf_num).unwrap().1 as usize) |
| .unwrap(); |
| let exclusive = !desc.readonly; |
| let (stages, access) = desc.pipeline_stages_and_access(); |
| resources.push(( |
| KeyTy::Buffer, |
| Some(( |
| PipelineMemoryAccess { |
| stages, |
| access, |
| exclusive, |
| }, |
| ImageLayout::Undefined, |
| ImageLayout::Undefined, |
| ImageUninitializedSafe::Unsafe, |
| )), |
| )); |
| } |
| for img_num in 0..ds.num_images() { |
| let (image_view, desc_num) = ds.image(img_num).unwrap(); |
| let desc = ds.layout().descriptor(desc_num as usize).unwrap(); |
| let exclusive = !desc.readonly; |
| let (stages, access) = desc.pipeline_stages_and_access(); |
| let mut ignore_me_hack = false; |
| let layouts = image_view |
| .image() |
| .descriptor_layouts() |
| .expect("descriptor_layouts must return Some when used in an image view"); |
| let layout = match desc.ty { |
| DescriptorDescTy::CombinedImageSampler(_) => layouts.combined_image_sampler, |
| DescriptorDescTy::Image(ref img) => { |
| if img.sampled { |
| layouts.sampled_image |
| } else { |
| layouts.storage_image |
| } |
| } |
| DescriptorDescTy::InputAttachment { .. } => { |
| // FIXME: This is tricky. Since we read from the input attachment |
| // and this input attachment is being written in an earlier pass, |
| // vulkano will think that it needs to put a pipeline barrier and will |
| // return a `Conflict` error. For now as a work-around we simply ignore |
| // input attachments. |
| ignore_me_hack = true; |
| layouts.input_attachment |
| } |
| _ => panic!("Tried to bind an image to a non-image descriptor"), |
| }; |
| resources.push(( |
| KeyTy::Image, |
| if ignore_me_hack { |
| None |
| } else { |
| Some(( |
| PipelineMemoryAccess { |
| stages, |
| access, |
| exclusive, |
| }, |
| layout, |
| layout, |
| ImageUninitializedSafe::Unsafe, |
| )) |
| }, |
| )); |
| } |
| } |
| |
| descriptor_sets |
| } |
| |
| fn add_vertex_buffer_resources( |
| &self, |
| resources: &mut Vec<( |
| KeyTy, |
| Option<( |
| PipelineMemoryAccess, |
| ImageLayout, |
| ImageLayout, |
| ImageUninitializedSafe, |
| )>, |
| )>, |
| vertex_input: &VertexInput, |
| ) -> SmallVec<[(u32, Arc<dyn Command + Send + Sync>); 4]> { |
| let vertex_buffers: SmallVec<[(u32, Arc<dyn Command + Send + Sync>); 4]> = vertex_input |
| .bindings() |
| .map(|(binding_num, _)| { |
| ( |
| binding_num, |
| self.bindings.vertex_buffers[&binding_num].clone(), |
| ) |
| }) |
| .collect(); |
| |
| resources.extend(vertex_buffers.iter().map(|_| { |
| ( |
| KeyTy::Buffer, |
| Some(( |
| PipelineMemoryAccess { |
| stages: PipelineStages { |
| vertex_input: true, |
| ..PipelineStages::none() |
| }, |
| access: AccessFlags { |
| vertex_attribute_read: true, |
| ..AccessFlags::none() |
| }, |
| exclusive: false, |
| }, |
| ImageLayout::Undefined, |
| ImageLayout::Undefined, |
| ImageUninitializedSafe::Unsafe, |
| )), |
| ) |
| })); |
| |
| vertex_buffers |
| } |
| |
| fn add_index_buffer_resources( |
| &self, |
| resources: &mut Vec<( |
| KeyTy, |
| Option<( |
| PipelineMemoryAccess, |
| ImageLayout, |
| ImageLayout, |
| ImageUninitializedSafe, |
| )>, |
| )>, |
| ) -> Arc<dyn Command + Send + Sync> { |
| let index_buffer = self.bindings.index_buffer.as_ref().unwrap().clone(); |
| |
| resources.push(( |
| KeyTy::Buffer, |
| Some(( |
| PipelineMemoryAccess { |
| stages: PipelineStages { |
| vertex_input: true, |
| ..PipelineStages::none() |
| }, |
| access: AccessFlags { |
| index_read: true, |
| ..AccessFlags::none() |
| }, |
| exclusive: false, |
| }, |
| ImageLayout::Undefined, |
| ImageLayout::Undefined, |
| ImageUninitializedSafe::Unsafe, |
| )), |
| )); |
| |
| index_buffer |
| } |
| |
| fn add_indirect_buffer_resources( |
| &self, |
| resources: &mut Vec<( |
| KeyTy, |
| Option<( |
| PipelineMemoryAccess, |
| ImageLayout, |
| ImageLayout, |
| ImageUninitializedSafe, |
| )>, |
| )>, |
| ) { |
| resources.push(( |
| KeyTy::Buffer, |
| Some(( |
| PipelineMemoryAccess { |
| stages: PipelineStages { |
| draw_indirect: true, |
| ..PipelineStages::none() |
| }, // TODO: is draw_indirect correct for dispatch too? |
| access: AccessFlags { |
| indirect_command_read: true, |
| ..AccessFlags::none() |
| }, |
| exclusive: false, |
| }, |
| ImageLayout::Undefined, |
| ImageLayout::Undefined, |
| ImageUninitializedSafe::Unsafe, |
| )), |
| )); |
| } |
| } |
| |
| pub struct SyncCommandBufferBuilderBindDescriptorSets<'b> { |
| builder: &'b mut SyncCommandBufferBuilder, |
| descriptor_sets: SmallVec<[DescriptorSetWithOffsets; 12]>, |
| } |
| |
| impl<'b> SyncCommandBufferBuilderBindDescriptorSets<'b> { |
| /// Adds a descriptor set to the list. |
| #[inline] |
| pub fn add<S>(&mut self, descriptor_set: S) |
| where |
| S: Into<DescriptorSetWithOffsets>, |
| { |
| self.descriptor_sets.push(descriptor_set.into()); |
| } |
| |
| #[inline] |
| pub unsafe fn submit( |
| self, |
| pipeline_bind_point: PipelineBindPoint, |
| pipeline_layout: Arc<PipelineLayout>, |
| first_binding: u32, |
| ) -> Result<(), SyncCommandBufferBuilderError> { |
| if self.descriptor_sets.is_empty() { |
| return Ok(()); |
| } |
| |
| struct Cmd { |
| descriptor_sets: SmallVec<[DescriptorSetWithOffsets; 12]>, |
| pipeline_bind_point: PipelineBindPoint, |
| pipeline_layout: Arc<PipelineLayout>, |
| first_binding: u32, |
| } |
| |
| impl Command for Cmd { |
| fn name(&self) -> &'static str { |
| "vkCmdBindDescriptorSets" |
| } |
| |
| 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() |
| .map(|x| x.as_ref().1.iter().copied()) |
| .flatten(); |
| |
| out.bind_descriptor_sets( |
| self.pipeline_bind_point, |
| &self.pipeline_layout, |
| self.first_binding, |
| descriptor_sets, |
| dynamic_offsets, |
| ); |
| } |
| |
| fn bound_descriptor_set(&self, set_num: u32) -> (&dyn DescriptorSet, &[u32]) { |
| let index = set_num.checked_sub(self.first_binding).unwrap() as usize; |
| self.descriptor_sets[index].as_ref() |
| } |
| } |
| |
| let num_descriptor_sets = self.descriptor_sets.len() as u32; |
| self.builder.append_command( |
| Cmd { |
| descriptor_sets: self.descriptor_sets, |
| pipeline_bind_point, |
| pipeline_layout, |
| first_binding, |
| }, |
| &[], |
| )?; |
| |
| let cmd = self.builder.commands.last().unwrap(); |
| let sets = self |
| .builder |
| .bindings |
| .descriptor_sets |
| .entry(pipeline_bind_point) |
| .or_default(); |
| sets.retain(|&set_num, _| set_num < first_binding); // Remove all descriptor sets with a higher number |
| |
| for i in 0..num_descriptor_sets { |
| sets.insert(first_binding + i, cmd.clone()); |
| } |
| |
| Ok(()) |
| } |
| } |
| |
| /// Prototype for a `vkCmdBindVertexBuffers`. |
| pub struct SyncCommandBufferBuilderBindVertexBuffer<'a> { |
| builder: &'a mut SyncCommandBufferBuilder, |
| inner: UnsafeCommandBufferBuilderBindVertexBuffer, |
| buffers: SmallVec<[Box<dyn BufferAccess + Send + Sync>; 4]>, |
| } |
| |
| impl<'a> SyncCommandBufferBuilderBindVertexBuffer<'a> { |
| /// Adds a buffer to the list. |
| #[inline] |
| pub fn add<B>(&mut self, buffer: B) |
| where |
| B: BufferAccess + Send + Sync + 'static, |
| { |
| self.inner.add(&buffer); |
| self.buffers.push(Box::new(buffer)); |
| } |
| |
| #[inline] |
| pub unsafe fn submit(self, first_binding: u32) -> Result<(), SyncCommandBufferBuilderError> { |
| struct Cmd { |
| first_binding: u32, |
| inner: Mutex<Option<UnsafeCommandBufferBuilderBindVertexBuffer>>, |
| buffers: SmallVec<[Box<dyn BufferAccess + Send + Sync>; 4]>, |
| } |
| |
| impl Command for Cmd { |
| fn name(&self) -> &'static str { |
| "vkCmdBindVertexBuffers" |
| } |
| |
| unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) { |
| out.bind_vertex_buffers( |
| self.first_binding, |
| self.inner.lock().unwrap().take().unwrap(), |
| ); |
| } |
| |
| fn bound_vertex_buffer(&self, binding_num: u32) -> &dyn BufferAccess { |
| let index = binding_num.checked_sub(self.first_binding).unwrap() as usize; |
| &self.buffers[index] |
| } |
| } |
| |
| let num_buffers = self.buffers.len() as u32; |
| self.builder.append_command( |
| Cmd { |
| first_binding, |
| inner: Mutex::new(Some(self.inner)), |
| buffers: self.buffers, |
| }, |
| &[], |
| )?; |
| |
| let cmd = self.builder.commands.last().unwrap(); |
| for i in 0..num_buffers { |
| self.builder |
| .bindings |
| .vertex_buffers |
| .insert(first_binding + i, cmd.clone()); |
| } |
| |
| Ok(()) |
| } |
| } |
| |
| /// Prototype for a `vkCmdExecuteCommands`. |
| pub struct SyncCommandBufferBuilderExecuteCommands<'a> { |
| builder: &'a mut SyncCommandBufferBuilder, |
| inner: Vec<Box<dyn SecondaryCommandBuffer + Send + Sync>>, |
| } |
| |
| impl<'a> SyncCommandBufferBuilderExecuteCommands<'a> { |
| /// Adds a command buffer to the list. |
| #[inline] |
| pub fn add<C>(&mut self, command_buffer: C) |
| where |
| C: SecondaryCommandBuffer + Send + Sync + 'static, |
| { |
| self.inner.push(Box::new(command_buffer)); |
| } |
| |
| #[inline] |
| pub unsafe fn submit(self) -> Result<(), SyncCommandBufferBuilderError> { |
| struct DropUnlock(Box<dyn SecondaryCommandBuffer + Send + Sync>); |
| impl std::ops::Deref for DropUnlock { |
| type Target = Box<dyn SecondaryCommandBuffer + Send + Sync>; |
| |
| fn deref(&self) -> &Self::Target { |
| &self.0 |
| } |
| } |
| unsafe impl SafeDeref for DropUnlock {} |
| |
| impl Drop for DropUnlock { |
| fn drop(&mut self) { |
| unsafe { |
| self.unlock(); |
| } |
| } |
| } |
| |
| struct Cmd(Vec<DropUnlock>); |
| |
| impl Command for Cmd { |
| fn name(&self) -> &'static str { |
| "vkCmdExecuteCommands" |
| } |
| |
| unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) { |
| let mut execute = UnsafeCommandBufferBuilderExecuteCommands::new(); |
| self.0 |
| .iter() |
| .for_each(|cbuf| execute.add_raw(cbuf.inner().internal_object())); |
| out.execute_commands(execute); |
| } |
| |
| fn buffer(&self, mut num: usize) -> &dyn BufferAccess { |
| for cbuf in self.0.iter() { |
| if let Some(buf) = cbuf.buffer(num) { |
| return buf.0; |
| } |
| num -= cbuf.num_buffers(); |
| } |
| panic!() |
| } |
| |
| fn buffer_name(&self, mut num: usize) -> Cow<'static, str> { |
| for (cbuf_num, cbuf) in self.0.iter().enumerate() { |
| if let Some(buf) = cbuf.buffer(num) { |
| return format!("Buffer bound to secondary command buffer {}", cbuf_num) |
| .into(); |
| } |
| num -= cbuf.num_buffers(); |
| } |
| panic!() |
| } |
| |
| fn image(&self, mut num: usize) -> &dyn ImageAccess { |
| for cbuf in self.0.iter() { |
| if let Some(img) = cbuf.image(num) { |
| return img.0; |
| } |
| num -= cbuf.num_images(); |
| } |
| panic!() |
| } |
| |
| fn image_name(&self, mut num: usize) -> Cow<'static, str> { |
| for (cbuf_num, cbuf) in self.0.iter().enumerate() { |
| if let Some(img) = cbuf.image(num) { |
| return format!("Image bound to secondary command buffer {}", cbuf_num) |
| .into(); |
| } |
| num -= cbuf.num_images(); |
| } |
| panic!() |
| } |
| } |
| |
| let resources = { |
| let mut resources = Vec::new(); |
| for cbuf in self.inner.iter() { |
| for buf_num in 0..cbuf.num_buffers() { |
| resources.push(( |
| KeyTy::Buffer, |
| Some(( |
| cbuf.buffer(buf_num).unwrap().1, |
| ImageLayout::Undefined, |
| ImageLayout::Undefined, |
| ImageUninitializedSafe::Unsafe, |
| )), |
| )); |
| } |
| for img_num in 0..cbuf.num_images() { |
| let (_, memory, start_layout, end_layout, image_uninitialized_safe) = |
| cbuf.image(img_num).unwrap(); |
| resources.push(( |
| KeyTy::Image, |
| Some((memory, start_layout, end_layout, image_uninitialized_safe)), |
| )); |
| } |
| } |
| resources |
| }; |
| |
| self.builder.append_command( |
| Cmd(self |
| .inner |
| .into_iter() |
| .map(|cbuf| { |
| cbuf.lock_record()?; |
| Ok(DropUnlock(cbuf)) |
| }) |
| .collect::<Result<Vec<_>, CommandBufferExecError>>()?), |
| &resources, |
| )?; |
| |
| Ok(()) |
| } |
| } |