1 // Copyright (c) 2016 The vulkano developers
2 // Licensed under the Apache License, Version 2.0
3 // <LICENSE-APACHE or
4 // https://www.apache.org/licenses/LICENSE-2.0> or the MIT
5 // license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
6 // at your option. All files in the project carrying such
7 // notice may not be copied, modified, or distributed except
8 // according to those terms.
9
10 use crate::buffer::BufferAccess;
11 use crate::buffer::TypedBufferAccess;
12 use crate::command_buffer::pool::standard::StandardCommandPoolAlloc;
13 use crate::command_buffer::pool::standard::StandardCommandPoolBuilder;
14 use crate::command_buffer::pool::CommandPool;
15 use crate::command_buffer::pool::CommandPoolBuilderAlloc;
16 use crate::command_buffer::synced::SyncCommandBuffer;
17 use crate::command_buffer::synced::SyncCommandBufferBuilder;
18 use crate::command_buffer::synced::SyncCommandBufferBuilderError;
19 use crate::command_buffer::sys::UnsafeCommandBuffer;
20 use crate::command_buffer::sys::UnsafeCommandBufferBuilderBufferImageCopy;
21 use crate::command_buffer::sys::UnsafeCommandBufferBuilderColorImageClear;
22 use crate::command_buffer::sys::UnsafeCommandBufferBuilderImageBlit;
23 use crate::command_buffer::sys::UnsafeCommandBufferBuilderImageCopy;
24 use crate::command_buffer::validity::*;
25 use crate::command_buffer::CommandBufferExecError;
26 use crate::command_buffer::CommandBufferInheritance;
27 use crate::command_buffer::CommandBufferInheritanceRenderPass;
28 use crate::command_buffer::CommandBufferLevel;
29 use crate::command_buffer::CommandBufferUsage;
30 use crate::command_buffer::DispatchIndirectCommand;
31 use crate::command_buffer::DrawIndexedIndirectCommand;
32 use crate::command_buffer::DrawIndirectCommand;
33 use crate::command_buffer::DynamicState;
34 use crate::command_buffer::ImageUninitializedSafe;
35 use crate::command_buffer::PrimaryCommandBuffer;
36 use crate::command_buffer::SecondaryCommandBuffer;
37 use crate::command_buffer::StateCacher;
38 use crate::command_buffer::StateCacherOutcome;
39 use crate::command_buffer::SubpassContents;
40 use crate::descriptor_set::DescriptorSetWithOffsets;
41 use crate::descriptor_set::DescriptorSetsCollection;
42 use crate::device::physical::QueueFamily;
43 use crate::device::Device;
44 use crate::device::DeviceOwned;
45 use crate::device::Queue;
46 use crate::format::ClearValue;
47 use crate::format::FormatTy;
48 use crate::format::Pixel;
49 use crate::image::ImageAccess;
50 use crate::image::ImageAspect;
51 use crate::image::ImageAspects;
52 use crate::image::ImageLayout;
53 use crate::pipeline::depth_stencil::StencilFaces;
54 use crate::pipeline::input_assembly::Index;
55 use crate::pipeline::layout::PipelineLayout;
56 use crate::pipeline::vertex::VertexSource;
57 use crate::pipeline::ComputePipelineAbstract;
58 use crate::pipeline::GraphicsPipelineAbstract;
59 use crate::pipeline::PipelineBindPoint;
60 use crate::query::QueryControlFlags;
61 use crate::query::QueryPipelineStatisticFlags;
62 use crate::query::QueryPool;
63 use crate::query::QueryResultElement;
64 use crate::query::QueryResultFlags;
65 use crate::query::QueryType;
66 use crate::render_pass::Framebuffer;
67 use crate::render_pass::FramebufferAbstract;
68 use crate::render_pass::LoadOp;
69 use crate::render_pass::RenderPass;
70 use crate::render_pass::Subpass;
71 use crate::sampler::Filter;
72 use crate::sync::AccessCheckError;
73 use crate::sync::AccessFlags;
74 use crate::sync::GpuFuture;
75 use crate::sync::PipelineMemoryAccess;
76 use crate::sync::PipelineStage;
77 use crate::sync::PipelineStages;
78 use crate::DeviceSize;
79 use crate::VulkanObject;
80 use crate::{OomError, SafeDeref};
81 use fnv::FnvHashMap;
82 use std::error;
83 use std::ffi::CStr;
84 use std::fmt;
85 use std::iter;
86 use std::marker::PhantomData;
87 use std::mem;
88 use std::ops::Range;
89 use std::slice;
90 use std::sync::atomic::AtomicBool;
91 use std::sync::atomic::Ordering;
92 use std::sync::Arc;
93
94 /// Note that command buffers allocated from the default command pool (`Arc<StandardCommandPool>`)
95 /// don't implement the `Send` and `Sync` traits. If you use this pool, then the
96 /// `AutoCommandBufferBuilder` will not implement `Send` and `Sync` either. Once a command buffer
97 /// is built, however, it *does* implement `Send` and `Sync`.
98 pub struct AutoCommandBufferBuilder<L, P = StandardCommandPoolBuilder> {
99 inner: SyncCommandBufferBuilder,
100 pool_builder_alloc: P, // Safety: must be dropped after `inner`
101 state_cacher: StateCacher,
102
103 // The queue family that this command buffer is being created for.
104 queue_family_id: u32,
105
106 // The inheritance for secondary command buffers.
107 inheritance: Option<CommandBufferInheritance<Box<dyn FramebufferAbstract + Send + Sync>>>,
108
109 // Usage flags passed when creating the command buffer.
110 usage: CommandBufferUsage,
111
112 // If we're inside a render pass, contains the render pass state.
113 render_pass_state: Option<RenderPassState>,
114
115 // If any queries are active, this hashmap contains their state.
116 query_state: FnvHashMap<ash::vk::QueryType, QueryState>,
117
118 _data: PhantomData<L>,
119 }
120
121 // The state of the current render pass, specifying the pass, subpass index and its intended contents.
122 struct RenderPassState {
123 subpass: (Arc<RenderPass>, u32),
124 contents: SubpassContents,
125 framebuffer: ash::vk::Framebuffer, // Always null for secondary command buffers
126 }
127
128 // The state of an active query.
129 struct QueryState {
130 query_pool: ash::vk::QueryPool,
131 query: u32,
132 ty: QueryType,
133 flags: QueryControlFlags,
134 in_subpass: bool,
135 }
136
137 impl AutoCommandBufferBuilder<PrimaryAutoCommandBuffer, StandardCommandPoolBuilder> {
138 /// Starts building a primary command buffer.
139 #[inline]
primary( device: Arc<Device>, queue_family: QueueFamily, usage: CommandBufferUsage, ) -> Result< AutoCommandBufferBuilder<PrimaryAutoCommandBuffer, StandardCommandPoolBuilder>, OomError, >140 pub fn primary(
141 device: Arc<Device>,
142 queue_family: QueueFamily,
143 usage: CommandBufferUsage,
144 ) -> Result<
145 AutoCommandBufferBuilder<PrimaryAutoCommandBuffer, StandardCommandPoolBuilder>,
146 OomError,
147 > {
148 AutoCommandBufferBuilder::with_level(
149 device,
150 queue_family,
151 usage,
152 CommandBufferLevel::primary(),
153 )
154 }
155 }
156
157 impl AutoCommandBufferBuilder<SecondaryAutoCommandBuffer, StandardCommandPoolBuilder> {
158 /// Starts building a secondary compute command buffer.
159 #[inline]
secondary_compute( device: Arc<Device>, queue_family: QueueFamily, usage: CommandBufferUsage, ) -> Result< AutoCommandBufferBuilder<SecondaryAutoCommandBuffer, StandardCommandPoolBuilder>, OomError, >160 pub fn secondary_compute(
161 device: Arc<Device>,
162 queue_family: QueueFamily,
163 usage: CommandBufferUsage,
164 ) -> Result<
165 AutoCommandBufferBuilder<SecondaryAutoCommandBuffer, StandardCommandPoolBuilder>,
166 OomError,
167 > {
168 let level = CommandBufferLevel::secondary(None, QueryPipelineStatisticFlags::none());
169 AutoCommandBufferBuilder::with_level(device, queue_family, usage, level)
170 }
171
172 /// Same as `secondary_compute`, but allows specifying how queries are being inherited.
173 #[inline]
secondary_compute_inherit_queries( device: Arc<Device>, queue_family: QueueFamily, usage: CommandBufferUsage, occlusion_query: Option<QueryControlFlags>, query_statistics_flags: QueryPipelineStatisticFlags, ) -> Result< AutoCommandBufferBuilder<SecondaryAutoCommandBuffer, StandardCommandPoolBuilder>, BeginError, >174 pub fn secondary_compute_inherit_queries(
175 device: Arc<Device>,
176 queue_family: QueueFamily,
177 usage: CommandBufferUsage,
178 occlusion_query: Option<QueryControlFlags>,
179 query_statistics_flags: QueryPipelineStatisticFlags,
180 ) -> Result<
181 AutoCommandBufferBuilder<SecondaryAutoCommandBuffer, StandardCommandPoolBuilder>,
182 BeginError,
183 > {
184 if occlusion_query.is_some() && !device.enabled_features().inherited_queries {
185 return Err(BeginError::InheritedQueriesFeatureNotEnabled);
186 }
187
188 if query_statistics_flags.count() > 0
189 && !device.enabled_features().pipeline_statistics_query
190 {
191 return Err(BeginError::PipelineStatisticsQueryFeatureNotEnabled);
192 }
193
194 let level = CommandBufferLevel::secondary(occlusion_query, query_statistics_flags);
195 Ok(AutoCommandBufferBuilder::with_level(
196 device,
197 queue_family,
198 usage,
199 level,
200 )?)
201 }
202
203 /// Starts building a secondary graphics command buffer.
204 #[inline]
secondary_graphics( device: Arc<Device>, queue_family: QueueFamily, usage: CommandBufferUsage, subpass: Subpass, ) -> Result< AutoCommandBufferBuilder<SecondaryAutoCommandBuffer, StandardCommandPoolBuilder>, OomError, >205 pub fn secondary_graphics(
206 device: Arc<Device>,
207 queue_family: QueueFamily,
208 usage: CommandBufferUsage,
209 subpass: Subpass,
210 ) -> Result<
211 AutoCommandBufferBuilder<SecondaryAutoCommandBuffer, StandardCommandPoolBuilder>,
212 OomError,
213 > {
214 let level = CommandBufferLevel::Secondary(CommandBufferInheritance {
215 render_pass: Some(CommandBufferInheritanceRenderPass {
216 subpass,
217 framebuffer: None::<Arc<Framebuffer<()>>>,
218 }),
219 occlusion_query: None,
220 query_statistics_flags: QueryPipelineStatisticFlags::none(),
221 });
222
223 AutoCommandBufferBuilder::with_level(device, queue_family, usage, level)
224 }
225
226 /// Same as `secondary_graphics`, but allows specifying how queries are being inherited.
227 #[inline]
secondary_graphics_inherit_queries( device: Arc<Device>, queue_family: QueueFamily, usage: CommandBufferUsage, subpass: Subpass, occlusion_query: Option<QueryControlFlags>, query_statistics_flags: QueryPipelineStatisticFlags, ) -> Result< AutoCommandBufferBuilder<SecondaryAutoCommandBuffer, StandardCommandPoolBuilder>, BeginError, >228 pub fn secondary_graphics_inherit_queries(
229 device: Arc<Device>,
230 queue_family: QueueFamily,
231 usage: CommandBufferUsage,
232 subpass: Subpass,
233 occlusion_query: Option<QueryControlFlags>,
234 query_statistics_flags: QueryPipelineStatisticFlags,
235 ) -> Result<
236 AutoCommandBufferBuilder<SecondaryAutoCommandBuffer, StandardCommandPoolBuilder>,
237 BeginError,
238 > {
239 if occlusion_query.is_some() && !device.enabled_features().inherited_queries {
240 return Err(BeginError::InheritedQueriesFeatureNotEnabled);
241 }
242
243 if query_statistics_flags.count() > 0
244 && !device.enabled_features().pipeline_statistics_query
245 {
246 return Err(BeginError::PipelineStatisticsQueryFeatureNotEnabled);
247 }
248
249 let level = CommandBufferLevel::Secondary(CommandBufferInheritance {
250 render_pass: Some(CommandBufferInheritanceRenderPass {
251 subpass,
252 framebuffer: None::<Arc<Framebuffer<()>>>,
253 }),
254 occlusion_query,
255 query_statistics_flags,
256 });
257
258 Ok(AutoCommandBufferBuilder::with_level(
259 device,
260 queue_family,
261 usage,
262 level,
263 )?)
264 }
265 }
266
267 impl<L> AutoCommandBufferBuilder<L, StandardCommandPoolBuilder> {
268 // Actual constructor. Private.
with_level<F>( device: Arc<Device>, queue_family: QueueFamily, usage: CommandBufferUsage, level: CommandBufferLevel<F>, ) -> Result<AutoCommandBufferBuilder<L, StandardCommandPoolBuilder>, OomError> where F: FramebufferAbstract + Clone + Send + Sync + 'static,269 fn with_level<F>(
270 device: Arc<Device>,
271 queue_family: QueueFamily,
272 usage: CommandBufferUsage,
273 level: CommandBufferLevel<F>,
274 ) -> Result<AutoCommandBufferBuilder<L, StandardCommandPoolBuilder>, OomError>
275 where
276 F: FramebufferAbstract + Clone + Send + Sync + 'static,
277 {
278 let (inheritance, render_pass_state) = match &level {
279 CommandBufferLevel::Primary => (None, None),
280 CommandBufferLevel::Secondary(inheritance) => {
281 let (render_pass, render_pass_state) = match inheritance.render_pass.as_ref() {
282 Some(CommandBufferInheritanceRenderPass {
283 subpass,
284 framebuffer,
285 }) => {
286 let render_pass = CommandBufferInheritanceRenderPass {
287 subpass: Subpass::from(subpass.render_pass().clone(), subpass.index())
288 .unwrap(),
289 framebuffer: framebuffer
290 .as_ref()
291 .map(|f| Box::new(f.clone()) as Box<_>),
292 };
293 let render_pass_state = RenderPassState {
294 subpass: (subpass.render_pass().clone(), subpass.index()),
295 contents: SubpassContents::Inline,
296 framebuffer: ash::vk::Framebuffer::null(), // Only needed for primary command buffers
297 };
298 (Some(render_pass), Some(render_pass_state))
299 }
300 None => (None, None),
301 };
302
303 (
304 Some(CommandBufferInheritance {
305 render_pass,
306 occlusion_query: inheritance.occlusion_query,
307 query_statistics_flags: inheritance.query_statistics_flags,
308 }),
309 render_pass_state,
310 )
311 }
312 };
313
314 unsafe {
315 let pool = Device::standard_command_pool(&device, queue_family);
316 let pool_builder_alloc = pool
317 .alloc(!matches!(level, CommandBufferLevel::Primary), 1)?
318 .next()
319 .expect("Requested one command buffer from the command pool, but got zero.");
320 let inner = SyncCommandBufferBuilder::new(pool_builder_alloc.inner(), level, usage)?;
321
322 Ok(AutoCommandBufferBuilder {
323 inner,
324 pool_builder_alloc,
325 state_cacher: StateCacher::new(),
326 queue_family_id: queue_family.id(),
327 render_pass_state,
328 query_state: FnvHashMap::default(),
329 inheritance,
330 usage,
331 _data: PhantomData,
332 })
333 }
334 }
335 }
336
337 #[derive(Clone, Copy, Debug)]
338 pub enum BeginError {
339 /// Occlusion query inheritance was requested, but the `inherited_queries` feature was not enabled.
340 InheritedQueriesFeatureNotEnabled,
341 /// Not enough memory.
342 OomError(OomError),
343 /// Pipeline statistics query inheritance was requested, but the `pipeline_statistics_query` feature was not enabled.
344 PipelineStatisticsQueryFeatureNotEnabled,
345 }
346
347 impl error::Error for BeginError {
348 #[inline]
source(&self) -> Option<&(dyn error::Error + 'static)>349 fn source(&self) -> Option<&(dyn error::Error + 'static)> {
350 match *self {
351 Self::OomError(ref err) => Some(err),
352 _ => None,
353 }
354 }
355 }
356
357 impl fmt::Display for BeginError {
358 #[inline]
fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error>359 fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
360 write!(
361 fmt,
362 "{}",
363 match *self {
364 Self::InheritedQueriesFeatureNotEnabled => {
365 "occlusion query inheritance was requested but the corresponding feature \
366 wasn't enabled"
367 }
368 Self::OomError(_) => "not enough memory available",
369 Self::PipelineStatisticsQueryFeatureNotEnabled => {
370 "pipeline statistics query inheritance was requested but the corresponding \
371 feature wasn't enabled"
372 }
373 }
374 )
375 }
376 }
377
378 impl From<OomError> for BeginError {
379 #[inline]
from(err: OomError) -> Self380 fn from(err: OomError) -> Self {
381 Self::OomError(err)
382 }
383 }
384
385 impl<P> AutoCommandBufferBuilder<PrimaryAutoCommandBuffer<P::Alloc>, P>
386 where
387 P: CommandPoolBuilderAlloc,
388 {
389 /// Builds the command buffer.
390 #[inline]
build(self) -> Result<PrimaryAutoCommandBuffer<P::Alloc>, BuildError>391 pub fn build(self) -> Result<PrimaryAutoCommandBuffer<P::Alloc>, BuildError> {
392 if self.render_pass_state.is_some() {
393 return Err(AutoCommandBufferBuilderContextError::ForbiddenInsideRenderPass.into());
394 }
395
396 if !self.query_state.is_empty() {
397 return Err(AutoCommandBufferBuilderContextError::QueryIsActive.into());
398 }
399
400 let submit_state = match self.usage {
401 CommandBufferUsage::MultipleSubmit => SubmitState::ExclusiveUse {
402 in_use: AtomicBool::new(false),
403 },
404 CommandBufferUsage::SimultaneousUse => SubmitState::Concurrent,
405 CommandBufferUsage::OneTimeSubmit => SubmitState::OneTime {
406 already_submitted: AtomicBool::new(false),
407 },
408 };
409
410 Ok(PrimaryAutoCommandBuffer {
411 inner: self.inner.build()?,
412 pool_alloc: self.pool_builder_alloc.into_alloc(),
413 submit_state,
414 })
415 }
416 }
417
418 impl<P> AutoCommandBufferBuilder<SecondaryAutoCommandBuffer<P::Alloc>, P>
419 where
420 P: CommandPoolBuilderAlloc,
421 {
422 /// Builds the command buffer.
423 #[inline]
build(self) -> Result<SecondaryAutoCommandBuffer<P::Alloc>, BuildError>424 pub fn build(self) -> Result<SecondaryAutoCommandBuffer<P::Alloc>, BuildError> {
425 if !self.query_state.is_empty() {
426 return Err(AutoCommandBufferBuilderContextError::QueryIsActive.into());
427 }
428
429 let submit_state = match self.usage {
430 CommandBufferUsage::MultipleSubmit => SubmitState::ExclusiveUse {
431 in_use: AtomicBool::new(false),
432 },
433 CommandBufferUsage::SimultaneousUse => SubmitState::Concurrent,
434 CommandBufferUsage::OneTimeSubmit => SubmitState::OneTime {
435 already_submitted: AtomicBool::new(false),
436 },
437 };
438
439 Ok(SecondaryAutoCommandBuffer {
440 inner: self.inner.build()?,
441 pool_alloc: self.pool_builder_alloc.into_alloc(),
442 inheritance: self.inheritance.unwrap(),
443 submit_state,
444 })
445 }
446 }
447
448 impl<L, P> AutoCommandBufferBuilder<L, P> {
449 #[inline]
ensure_outside_render_pass(&self) -> Result<(), AutoCommandBufferBuilderContextError>450 fn ensure_outside_render_pass(&self) -> Result<(), AutoCommandBufferBuilderContextError> {
451 if self.render_pass_state.is_some() {
452 return Err(AutoCommandBufferBuilderContextError::ForbiddenInsideRenderPass);
453 }
454
455 Ok(())
456 }
457
458 #[inline]
ensure_inside_render_pass_inline<Gp>( &self, pipeline: &Gp, ) -> Result<(), AutoCommandBufferBuilderContextError> where Gp: ?Sized + GraphicsPipelineAbstract,459 fn ensure_inside_render_pass_inline<Gp>(
460 &self,
461 pipeline: &Gp,
462 ) -> Result<(), AutoCommandBufferBuilderContextError>
463 where
464 Gp: ?Sized + GraphicsPipelineAbstract,
465 {
466 let render_pass_state = self
467 .render_pass_state
468 .as_ref()
469 .ok_or(AutoCommandBufferBuilderContextError::ForbiddenOutsideRenderPass)?;
470
471 // Subpass must be for inline commands
472 if render_pass_state.contents != SubpassContents::Inline {
473 return Err(AutoCommandBufferBuilderContextError::WrongSubpassType);
474 }
475
476 // Subpasses must be the same.
477 if pipeline.subpass().index() != render_pass_state.subpass.1 {
478 return Err(AutoCommandBufferBuilderContextError::WrongSubpassIndex);
479 }
480
481 // Render passes must be compatible.
482 if !pipeline
483 .subpass()
484 .render_pass()
485 .desc()
486 .is_compatible_with_desc(&render_pass_state.subpass.0.desc())
487 {
488 return Err(AutoCommandBufferBuilderContextError::IncompatibleRenderPass);
489 }
490
491 Ok(())
492 }
493
494 #[inline]
queue_family(&self) -> QueueFamily495 fn queue_family(&self) -> QueueFamily {
496 self.device()
497 .physical_device()
498 .queue_family_by_id(self.queue_family_id)
499 .unwrap()
500 }
501
502 /// Adds a command that copies an image to another.
503 ///
504 /// Copy operations have several restrictions:
505 ///
506 /// - Copy operations are only allowed on queue families that support transfer, graphics, or
507 /// compute operations.
508 /// - The number of samples in the source and destination images must be equal.
509 /// - The size of the uncompressed element format of the source image must be equal to the
510 /// compressed element format of the destination.
511 /// - If you copy between depth, stencil or depth-stencil images, the format of both images
512 /// must match exactly.
513 /// - For two-dimensional images, the Z coordinate must be 0 for the image offsets and 1 for
514 /// the extent. Same for the Y coordinate for one-dimensional images.
515 /// - For non-array images, the base array layer must be 0 and the number of layers must be 1.
516 ///
517 /// If `layer_count` is greater than 1, the copy will happen between each individual layer as
518 /// if they were separate images.
519 ///
520 /// # Panic
521 ///
522 /// - Panics if the source or the destination was not created with `device`.
523 ///
copy_image<S, D>( &mut self, source: S, source_offset: [i32; 3], source_base_array_layer: u32, source_mip_level: u32, destination: D, destination_offset: [i32; 3], destination_base_array_layer: u32, destination_mip_level: u32, extent: [u32; 3], layer_count: u32, ) -> Result<&mut Self, CopyImageError> where S: ImageAccess + Send + Sync + 'static, D: ImageAccess + Send + Sync + 'static,524 pub fn copy_image<S, D>(
525 &mut self,
526 source: S,
527 source_offset: [i32; 3],
528 source_base_array_layer: u32,
529 source_mip_level: u32,
530 destination: D,
531 destination_offset: [i32; 3],
532 destination_base_array_layer: u32,
533 destination_mip_level: u32,
534 extent: [u32; 3],
535 layer_count: u32,
536 ) -> Result<&mut Self, CopyImageError>
537 where
538 S: ImageAccess + Send + Sync + 'static,
539 D: ImageAccess + Send + Sync + 'static,
540 {
541 unsafe {
542 self.ensure_outside_render_pass()?;
543
544 check_copy_image(
545 self.device(),
546 &source,
547 source_offset,
548 source_base_array_layer,
549 source_mip_level,
550 &destination,
551 destination_offset,
552 destination_base_array_layer,
553 destination_mip_level,
554 extent,
555 layer_count,
556 )?;
557
558 let copy = UnsafeCommandBufferBuilderImageCopy {
559 // TODO: Allowing choosing a subset of the image aspects, but note that if color
560 // is included, neither depth nor stencil may.
561 aspects: ImageAspects {
562 color: source.has_color(),
563 depth: !source.has_color() && source.has_depth() && destination.has_depth(),
564 stencil: !source.has_color()
565 && source.has_stencil()
566 && destination.has_stencil(),
567 ..ImageAspects::none()
568 },
569 source_mip_level,
570 destination_mip_level,
571 source_base_array_layer,
572 destination_base_array_layer,
573 layer_count,
574 source_offset,
575 destination_offset,
576 extent,
577 };
578
579 // TODO: Allow choosing layouts, but note that only Transfer*Optimal and General are
580 // valid.
581 self.inner.copy_image(
582 source,
583 ImageLayout::TransferSrcOptimal,
584 destination,
585 ImageLayout::TransferDstOptimal,
586 iter::once(copy),
587 )?;
588 Ok(self)
589 }
590 }
591
592 /// Adds a command that blits an image to another.
593 ///
594 /// A *blit* is similar to an image copy operation, except that the portion of the image that
595 /// is transferred can be resized. You choose an area of the source and an area of the
596 /// destination, and the implementation will resize the area of the source so that it matches
597 /// the size of the area of the destination before writing it.
598 ///
599 /// Blit operations have several restrictions:
600 ///
601 /// - Blit operations are only allowed on queue families that support graphics operations.
602 /// - The format of the source and destination images must support blit operations, which
603 /// depends on the Vulkan implementation. Vulkan guarantees that some specific formats must
604 /// always be supported. See tables 52 to 61 of the specifications.
605 /// - Only single-sampled images are allowed.
606 /// - You can only blit between two images whose formats belong to the same type. The types
607 /// are: floating-point, signed integers, unsigned integers, depth-stencil.
608 /// - If you blit between depth, stencil or depth-stencil images, the format of both images
609 /// must match exactly.
610 /// - If you blit between depth, stencil or depth-stencil images, only the `Nearest` filter is
611 /// allowed.
612 /// - For two-dimensional images, the Z coordinate must be 0 for the top-left offset and 1 for
613 /// the bottom-right offset. Same for the Y coordinate for one-dimensional images.
614 /// - For non-array images, the base array layer must be 0 and the number of layers must be 1.
615 ///
616 /// If `layer_count` is greater than 1, the blit will happen between each individual layer as
617 /// if they were separate images.
618 ///
619 /// # Panic
620 ///
621 /// - Panics if the source or the destination was not created with `device`.
622 ///
blit_image<S, D>( &mut self, source: S, source_top_left: [i32; 3], source_bottom_right: [i32; 3], source_base_array_layer: u32, source_mip_level: u32, destination: D, destination_top_left: [i32; 3], destination_bottom_right: [i32; 3], destination_base_array_layer: u32, destination_mip_level: u32, layer_count: u32, filter: Filter, ) -> Result<&mut Self, BlitImageError> where S: ImageAccess + Send + Sync + 'static, D: ImageAccess + Send + Sync + 'static,623 pub fn blit_image<S, D>(
624 &mut self,
625 source: S,
626 source_top_left: [i32; 3],
627 source_bottom_right: [i32; 3],
628 source_base_array_layer: u32,
629 source_mip_level: u32,
630 destination: D,
631 destination_top_left: [i32; 3],
632 destination_bottom_right: [i32; 3],
633 destination_base_array_layer: u32,
634 destination_mip_level: u32,
635 layer_count: u32,
636 filter: Filter,
637 ) -> Result<&mut Self, BlitImageError>
638 where
639 S: ImageAccess + Send + Sync + 'static,
640 D: ImageAccess + Send + Sync + 'static,
641 {
642 unsafe {
643 if !self.queue_family().supports_graphics() {
644 return Err(AutoCommandBufferBuilderContextError::NotSupportedByQueueFamily.into());
645 }
646
647 self.ensure_outside_render_pass()?;
648
649 check_blit_image(
650 self.device(),
651 &source,
652 source_top_left,
653 source_bottom_right,
654 source_base_array_layer,
655 source_mip_level,
656 &destination,
657 destination_top_left,
658 destination_bottom_right,
659 destination_base_array_layer,
660 destination_mip_level,
661 layer_count,
662 filter,
663 )?;
664
665 let blit = UnsafeCommandBufferBuilderImageBlit {
666 // TODO:
667 aspects: if source.has_color() {
668 ImageAspects {
669 color: true,
670 ..ImageAspects::none()
671 }
672 } else {
673 unimplemented!()
674 },
675 source_mip_level,
676 destination_mip_level,
677 source_base_array_layer,
678 destination_base_array_layer,
679 layer_count,
680 source_top_left,
681 source_bottom_right,
682 destination_top_left,
683 destination_bottom_right,
684 };
685
686 self.inner.blit_image(
687 source,
688 ImageLayout::TransferSrcOptimal,
689 destination, // TODO: let choose layout
690 ImageLayout::TransferDstOptimal,
691 iter::once(blit),
692 filter,
693 )?;
694 Ok(self)
695 }
696 }
697
698 /// Adds a command that clears all the layers and mipmap levels of a color image with a
699 /// specific value.
700 ///
701 /// # Panic
702 ///
703 /// Panics if `color` is not a color value.
704 ///
clear_color_image<I>( &mut self, image: I, color: ClearValue, ) -> Result<&mut Self, ClearColorImageError> where I: ImageAccess + Send + Sync + 'static,705 pub fn clear_color_image<I>(
706 &mut self,
707 image: I,
708 color: ClearValue,
709 ) -> Result<&mut Self, ClearColorImageError>
710 where
711 I: ImageAccess + Send + Sync + 'static,
712 {
713 let layers = image.dimensions().array_layers();
714 let levels = image.mipmap_levels();
715
716 self.clear_color_image_dimensions(image, 0, layers, 0, levels, color)
717 }
718
719 /// Adds a command that clears a color image with a specific value.
720 ///
721 /// # Panic
722 ///
723 /// - Panics if `color` is not a color value.
724 ///
clear_color_image_dimensions<I>( &mut self, image: I, first_layer: u32, num_layers: u32, first_mipmap: u32, num_mipmaps: u32, color: ClearValue, ) -> Result<&mut Self, ClearColorImageError> where I: ImageAccess + Send + Sync + 'static,725 pub fn clear_color_image_dimensions<I>(
726 &mut self,
727 image: I,
728 first_layer: u32,
729 num_layers: u32,
730 first_mipmap: u32,
731 num_mipmaps: u32,
732 color: ClearValue,
733 ) -> Result<&mut Self, ClearColorImageError>
734 where
735 I: ImageAccess + Send + Sync + 'static,
736 {
737 unsafe {
738 if !self.queue_family().supports_graphics() && !self.queue_family().supports_compute() {
739 return Err(AutoCommandBufferBuilderContextError::NotSupportedByQueueFamily.into());
740 }
741
742 self.ensure_outside_render_pass()?;
743 check_clear_color_image(
744 self.device(),
745 &image,
746 first_layer,
747 num_layers,
748 first_mipmap,
749 num_mipmaps,
750 )?;
751
752 match color {
753 ClearValue::Float(_) | ClearValue::Int(_) | ClearValue::Uint(_) => {}
754 _ => panic!("The clear color is not a color value"),
755 };
756
757 let region = UnsafeCommandBufferBuilderColorImageClear {
758 base_mip_level: first_mipmap,
759 level_count: num_mipmaps,
760 base_array_layer: first_layer,
761 layer_count: num_layers,
762 };
763
764 // TODO: let choose layout
765 self.inner.clear_color_image(
766 image,
767 ImageLayout::TransferDstOptimal,
768 color,
769 iter::once(region),
770 )?;
771 Ok(self)
772 }
773 }
774
775 /// Adds a command that copies from a buffer to another.
776 ///
777 /// This command will copy from the source to the destination. If their size is not equal, then
778 /// the amount of data copied is equal to the smallest of the two.
779 #[inline]
copy_buffer<S, D, T>( &mut self, source: S, destination: D, ) -> Result<&mut Self, CopyBufferError> where S: TypedBufferAccess<Content = T> + Send + Sync + 'static, D: TypedBufferAccess<Content = T> + Send + Sync + 'static, T: ?Sized,780 pub fn copy_buffer<S, D, T>(
781 &mut self,
782 source: S,
783 destination: D,
784 ) -> Result<&mut Self, CopyBufferError>
785 where
786 S: TypedBufferAccess<Content = T> + Send + Sync + 'static,
787 D: TypedBufferAccess<Content = T> + Send + Sync + 'static,
788 T: ?Sized,
789 {
790 unsafe {
791 self.ensure_outside_render_pass()?;
792 let infos = check_copy_buffer(self.device(), &source, &destination)?;
793 self.inner
794 .copy_buffer(source, destination, iter::once((0, 0, infos.copy_size)))?;
795 Ok(self)
796 }
797 }
798
799 /// Adds a command that copies a range from the source to the destination buffer.
800 /// Panics if out of bounds.
801 #[inline]
copy_buffer_dimensions<S, D, T>( &mut self, source: S, source_offset: DeviceSize, destination: D, destination_offset: DeviceSize, count: DeviceSize, ) -> Result<&mut Self, CopyBufferError> where S: TypedBufferAccess<Content = [T]> + Send + Sync + 'static, D: TypedBufferAccess<Content = [T]> + Send + Sync + 'static,802 pub fn copy_buffer_dimensions<S, D, T>(
803 &mut self,
804 source: S,
805 source_offset: DeviceSize,
806 destination: D,
807 destination_offset: DeviceSize,
808 count: DeviceSize,
809 ) -> Result<&mut Self, CopyBufferError>
810 where
811 S: TypedBufferAccess<Content = [T]> + Send + Sync + 'static,
812 D: TypedBufferAccess<Content = [T]> + Send + Sync + 'static,
813 {
814 self.ensure_outside_render_pass()?;
815
816 let _infos = check_copy_buffer(self.device(), &source, &destination)?;
817 debug_assert!(source_offset + count <= source.len());
818 debug_assert!(destination_offset + count <= destination.len());
819
820 let size = std::mem::size_of::<T>() as DeviceSize;
821 unsafe {
822 self.inner.copy_buffer(
823 source,
824 destination,
825 iter::once((
826 source_offset * size,
827 destination_offset * size,
828 count * size,
829 )),
830 )?;
831 }
832 Ok(self)
833 }
834
835 /// Adds a command that copies from a buffer to an image.
copy_buffer_to_image<S, D, Px>( &mut self, source: S, destination: D, ) -> Result<&mut Self, CopyBufferImageError> where S: TypedBufferAccess<Content = [Px]> + Send + Sync + 'static, D: ImageAccess + Send + Sync + 'static, Px: Pixel,836 pub fn copy_buffer_to_image<S, D, Px>(
837 &mut self,
838 source: S,
839 destination: D,
840 ) -> Result<&mut Self, CopyBufferImageError>
841 where
842 S: TypedBufferAccess<Content = [Px]> + Send + Sync + 'static,
843 D: ImageAccess + Send + Sync + 'static,
844 Px: Pixel,
845 {
846 self.ensure_outside_render_pass()?;
847
848 let dims = destination.dimensions().width_height_depth();
849 self.copy_buffer_to_image_dimensions(source, destination, [0, 0, 0], dims, 0, 1, 0)
850 }
851
852 /// Adds a command that copies from a buffer to an image.
copy_buffer_to_image_dimensions<S, D, Px>( &mut self, source: S, destination: D, offset: [u32; 3], size: [u32; 3], first_layer: u32, num_layers: u32, mipmap: u32, ) -> Result<&mut Self, CopyBufferImageError> where S: TypedBufferAccess<Content = [Px]> + Send + Sync + 'static, D: ImageAccess + Send + Sync + 'static, Px: Pixel,853 pub fn copy_buffer_to_image_dimensions<S, D, Px>(
854 &mut self,
855 source: S,
856 destination: D,
857 offset: [u32; 3],
858 size: [u32; 3],
859 first_layer: u32,
860 num_layers: u32,
861 mipmap: u32,
862 ) -> Result<&mut Self, CopyBufferImageError>
863 where
864 S: TypedBufferAccess<Content = [Px]> + Send + Sync + 'static,
865 D: ImageAccess + Send + Sync + 'static,
866 Px: Pixel,
867 {
868 unsafe {
869 self.ensure_outside_render_pass()?;
870
871 check_copy_buffer_image(
872 self.device(),
873 &source,
874 &destination,
875 CheckCopyBufferImageTy::BufferToImage,
876 offset,
877 size,
878 first_layer,
879 num_layers,
880 mipmap,
881 )?;
882
883 let copy = UnsafeCommandBufferBuilderBufferImageCopy {
884 buffer_offset: 0,
885 buffer_row_length: 0,
886 buffer_image_height: 0,
887 image_aspect: if destination.has_color() {
888 ImageAspect::Color
889 } else {
890 unimplemented!()
891 },
892 image_mip_level: mipmap,
893 image_base_array_layer: first_layer,
894 image_layer_count: num_layers,
895 image_offset: [offset[0] as i32, offset[1] as i32, offset[2] as i32],
896 image_extent: size,
897 };
898
899 self.inner.copy_buffer_to_image(
900 source,
901 destination,
902 ImageLayout::TransferDstOptimal, // TODO: let choose layout
903 iter::once(copy),
904 )?;
905 Ok(self)
906 }
907 }
908
909 /// Adds a command that copies from an image to a buffer.
910 // The data layout of the image on the gpu is opaque, as in, it is non of our business how the gpu stores the image.
911 // This does not matter since the act of copying the image into a buffer converts it to linear form.
copy_image_to_buffer<S, D, Px>( &mut self, source: S, destination: D, ) -> Result<&mut Self, CopyBufferImageError> where S: ImageAccess + Send + Sync + 'static, D: TypedBufferAccess<Content = [Px]> + Send + Sync + 'static, Px: Pixel,912 pub fn copy_image_to_buffer<S, D, Px>(
913 &mut self,
914 source: S,
915 destination: D,
916 ) -> Result<&mut Self, CopyBufferImageError>
917 where
918 S: ImageAccess + Send + Sync + 'static,
919 D: TypedBufferAccess<Content = [Px]> + Send + Sync + 'static,
920 Px: Pixel,
921 {
922 self.ensure_outside_render_pass()?;
923
924 let dims = source.dimensions().width_height_depth();
925 self.copy_image_to_buffer_dimensions(source, destination, [0, 0, 0], dims, 0, 1, 0)
926 }
927
928 /// Adds a command that copies from an image to a buffer.
copy_image_to_buffer_dimensions<S, D, Px>( &mut self, source: S, destination: D, offset: [u32; 3], size: [u32; 3], first_layer: u32, num_layers: u32, mipmap: u32, ) -> Result<&mut Self, CopyBufferImageError> where S: ImageAccess + Send + Sync + 'static, D: TypedBufferAccess<Content = [Px]> + Send + Sync + 'static, Px: Pixel,929 pub fn copy_image_to_buffer_dimensions<S, D, Px>(
930 &mut self,
931 source: S,
932 destination: D,
933 offset: [u32; 3],
934 size: [u32; 3],
935 first_layer: u32,
936 num_layers: u32,
937 mipmap: u32,
938 ) -> Result<&mut Self, CopyBufferImageError>
939 where
940 S: ImageAccess + Send + Sync + 'static,
941 D: TypedBufferAccess<Content = [Px]> + Send + Sync + 'static,
942 Px: Pixel,
943 {
944 unsafe {
945 self.ensure_outside_render_pass()?;
946
947 check_copy_buffer_image(
948 self.device(),
949 &destination,
950 &source,
951 CheckCopyBufferImageTy::ImageToBuffer,
952 offset,
953 size,
954 first_layer,
955 num_layers,
956 mipmap,
957 )?;
958
959 let copy = UnsafeCommandBufferBuilderBufferImageCopy {
960 buffer_offset: 0,
961 buffer_row_length: 0,
962 buffer_image_height: 0,
963 // TODO: Allow the user to choose aspect
964 image_aspect: if source.has_color() {
965 ImageAspect::Color
966 } else if source.has_depth() {
967 ImageAspect::Depth
968 } else if source.has_stencil() {
969 ImageAspect::Stencil
970 } else {
971 unimplemented!()
972 },
973 image_mip_level: mipmap,
974 image_base_array_layer: first_layer,
975 image_layer_count: num_layers,
976 image_offset: [offset[0] as i32, offset[1] as i32, offset[2] as i32],
977 image_extent: size,
978 };
979
980 self.inner.copy_image_to_buffer(
981 source,
982 ImageLayout::TransferSrcOptimal,
983 destination, // TODO: let choose layout
984 iter::once(copy),
985 )?;
986 Ok(self)
987 }
988 }
989
990 /// Open a command buffer debug label region.
991 ///
992 /// Note: you need to enable `VK_EXT_debug_utils` extension when creating an instance.
993 #[inline]
debug_marker_begin( &mut self, name: &'static CStr, color: [f32; 4], ) -> Result<&mut Self, DebugMarkerError>994 pub fn debug_marker_begin(
995 &mut self,
996 name: &'static CStr,
997 color: [f32; 4],
998 ) -> Result<&mut Self, DebugMarkerError> {
999 if !self.queue_family().supports_graphics() && self.queue_family().supports_compute() {
1000 return Err(AutoCommandBufferBuilderContextError::NotSupportedByQueueFamily.into());
1001 }
1002
1003 check_debug_marker_color(color)?;
1004
1005 unsafe {
1006 self.inner.debug_marker_begin(name.into(), color);
1007 }
1008
1009 Ok(self)
1010 }
1011
1012 /// Close a command buffer label region.
1013 ///
1014 /// Note: you need to open a command buffer label region first with `debug_marker_begin`.
1015 /// Note: you need to enable `VK_EXT_debug_utils` extension when creating an instance.
1016 #[inline]
debug_marker_end(&mut self) -> Result<&mut Self, DebugMarkerError>1017 pub fn debug_marker_end(&mut self) -> Result<&mut Self, DebugMarkerError> {
1018 if !self.queue_family().supports_graphics() && self.queue_family().supports_compute() {
1019 return Err(AutoCommandBufferBuilderContextError::NotSupportedByQueueFamily.into());
1020 }
1021
1022 // TODO: validate that debug_marker_begin with same name was sent earlier
1023
1024 unsafe {
1025 self.inner.debug_marker_end();
1026 }
1027
1028 Ok(self)
1029 }
1030
1031 /// Insert a label into a command buffer.
1032 ///
1033 /// Note: you need to enable `VK_EXT_debug_utils` extension when creating an instance.
1034 #[inline]
debug_marker_insert( &mut self, name: &'static CStr, color: [f32; 4], ) -> Result<&mut Self, DebugMarkerError>1035 pub fn debug_marker_insert(
1036 &mut self,
1037 name: &'static CStr,
1038 color: [f32; 4],
1039 ) -> Result<&mut Self, DebugMarkerError> {
1040 if !self.queue_family().supports_graphics() && self.queue_family().supports_compute() {
1041 return Err(AutoCommandBufferBuilderContextError::NotSupportedByQueueFamily.into());
1042 }
1043
1044 check_debug_marker_color(color)?;
1045
1046 unsafe {
1047 self.inner.debug_marker_insert(name.into(), color);
1048 }
1049
1050 Ok(self)
1051 }
1052
1053 /// Perform a single compute operation using a compute pipeline.
1054 #[inline]
dispatch<Cp, S, Pc>( &mut self, group_counts: [u32; 3], pipeline: Cp, descriptor_sets: S, push_constants: Pc, ) -> Result<&mut Self, DispatchError> where Cp: ComputePipelineAbstract + Send + Sync + 'static + Clone, S: DescriptorSetsCollection,1055 pub fn dispatch<Cp, S, Pc>(
1056 &mut self,
1057 group_counts: [u32; 3],
1058 pipeline: Cp,
1059 descriptor_sets: S,
1060 push_constants: Pc,
1061 ) -> Result<&mut Self, DispatchError>
1062 where
1063 Cp: ComputePipelineAbstract + Send + Sync + 'static + Clone, // TODO: meh for Clone
1064 S: DescriptorSetsCollection,
1065 {
1066 let descriptor_sets = descriptor_sets.into_vec();
1067
1068 unsafe {
1069 if !self.queue_family().supports_compute() {
1070 return Err(AutoCommandBufferBuilderContextError::NotSupportedByQueueFamily.into());
1071 }
1072
1073 self.ensure_outside_render_pass()?;
1074 check_push_constants_validity(pipeline.layout(), &push_constants)?;
1075 check_descriptor_sets_validity(pipeline.layout(), &descriptor_sets)?;
1076 check_dispatch(pipeline.device(), group_counts)?;
1077
1078 if let StateCacherOutcome::NeedChange =
1079 self.state_cacher.bind_compute_pipeline(&pipeline)
1080 {
1081 self.inner.bind_pipeline_compute(pipeline.clone());
1082 }
1083
1084 set_push_constants(&mut self.inner, pipeline.layout(), push_constants);
1085 bind_descriptor_sets(
1086 &mut self.inner,
1087 &mut self.state_cacher,
1088 PipelineBindPoint::Compute,
1089 pipeline.layout(),
1090 descriptor_sets,
1091 )?;
1092
1093 self.inner.dispatch(group_counts);
1094 Ok(self)
1095 }
1096 }
1097
1098 /// Perform multiple compute operations using a compute pipeline. One dispatch is performed for
1099 /// each `vulkano::command_buffer::DispatchIndirectCommand` struct in `indirect_buffer`.
1100 #[inline]
dispatch_indirect<Inb, Cp, S, Pc>( &mut self, indirect_buffer: Inb, pipeline: Cp, descriptor_sets: S, push_constants: Pc, ) -> Result<&mut Self, DispatchIndirectError> where Inb: BufferAccess + TypedBufferAccess<Content = [DispatchIndirectCommand]> + Send + Sync + 'static, Cp: ComputePipelineAbstract + Send + Sync + 'static + Clone, S: DescriptorSetsCollection,1101 pub fn dispatch_indirect<Inb, Cp, S, Pc>(
1102 &mut self,
1103 indirect_buffer: Inb,
1104 pipeline: Cp,
1105 descriptor_sets: S,
1106 push_constants: Pc,
1107 ) -> Result<&mut Self, DispatchIndirectError>
1108 where
1109 Inb: BufferAccess
1110 + TypedBufferAccess<Content = [DispatchIndirectCommand]>
1111 + Send
1112 + Sync
1113 + 'static,
1114 Cp: ComputePipelineAbstract + Send + Sync + 'static + Clone, // TODO: meh for Clone
1115 S: DescriptorSetsCollection,
1116 {
1117 let descriptor_sets = descriptor_sets.into_vec();
1118
1119 unsafe {
1120 if !self.queue_family().supports_compute() {
1121 return Err(AutoCommandBufferBuilderContextError::NotSupportedByQueueFamily.into());
1122 }
1123
1124 self.ensure_outside_render_pass()?;
1125 check_indirect_buffer(self.device(), &indirect_buffer)?;
1126 check_push_constants_validity(pipeline.layout(), &push_constants)?;
1127 check_descriptor_sets_validity(pipeline.layout(), &descriptor_sets)?;
1128
1129 if let StateCacherOutcome::NeedChange =
1130 self.state_cacher.bind_compute_pipeline(&pipeline)
1131 {
1132 self.inner.bind_pipeline_compute(pipeline.clone());
1133 }
1134
1135 set_push_constants(&mut self.inner, pipeline.layout(), push_constants);
1136 bind_descriptor_sets(
1137 &mut self.inner,
1138 &mut self.state_cacher,
1139 PipelineBindPoint::Compute,
1140 pipeline.layout(),
1141 descriptor_sets,
1142 )?;
1143
1144 self.inner.dispatch_indirect(indirect_buffer)?;
1145 Ok(self)
1146 }
1147 }
1148
1149 /// Perform a single draw operation using a graphics pipeline.
1150 ///
1151 /// `vertex_buffer` is a set of vertex and/or instance buffers used to provide input.
1152 ///
1153 /// All data in `vertex_buffer` is used for the draw operation. To use only some data in the
1154 /// buffer, wrap it in a `vulkano::buffer::BufferSlice`.
1155 #[inline]
draw<V, Gp, S, Pc>( &mut self, pipeline: Gp, dynamic: &DynamicState, vertex_buffers: V, descriptor_sets: S, push_constants: Pc, ) -> Result<&mut Self, DrawError> where Gp: GraphicsPipelineAbstract + VertexSource<V> + Send + Sync + 'static + Clone, S: DescriptorSetsCollection,1156 pub fn draw<V, Gp, S, Pc>(
1157 &mut self,
1158 pipeline: Gp,
1159 dynamic: &DynamicState,
1160 vertex_buffers: V,
1161 descriptor_sets: S,
1162 push_constants: Pc,
1163 ) -> Result<&mut Self, DrawError>
1164 where
1165 Gp: GraphicsPipelineAbstract + VertexSource<V> + Send + Sync + 'static + Clone, // TODO: meh for Clone
1166 S: DescriptorSetsCollection,
1167 {
1168 let descriptor_sets = descriptor_sets.into_vec();
1169
1170 unsafe {
1171 // TODO: must check that pipeline is compatible with render pass
1172
1173 self.ensure_inside_render_pass_inline(&pipeline)?;
1174 check_dynamic_state_validity(&pipeline, dynamic)?;
1175 check_push_constants_validity(pipeline.layout(), &push_constants)?;
1176 check_descriptor_sets_validity(pipeline.layout(), &descriptor_sets)?;
1177 let vb_infos = check_vertex_buffers(&pipeline, vertex_buffers)?;
1178
1179 if let StateCacherOutcome::NeedChange =
1180 self.state_cacher.bind_graphics_pipeline(&pipeline)
1181 {
1182 self.inner.bind_pipeline_graphics(pipeline.clone());
1183 }
1184
1185 let dynamic = self.state_cacher.dynamic_state(dynamic);
1186
1187 set_push_constants(&mut self.inner, pipeline.layout(), push_constants);
1188 set_state(&mut self.inner, &dynamic);
1189 bind_descriptor_sets(
1190 &mut self.inner,
1191 &mut self.state_cacher,
1192 PipelineBindPoint::Graphics,
1193 pipeline.layout(),
1194 descriptor_sets,
1195 )?;
1196 bind_vertex_buffers(
1197 &mut self.inner,
1198 &mut self.state_cacher,
1199 vb_infos.vertex_buffers,
1200 )?;
1201
1202 debug_assert!(self.queue_family().supports_graphics());
1203
1204 self.inner.draw(
1205 vb_infos.vertex_count as u32,
1206 vb_infos.instance_count as u32,
1207 0,
1208 0,
1209 );
1210 Ok(self)
1211 }
1212 }
1213
1214 /// Perform multiple draw operations using a graphics pipeline.
1215 ///
1216 /// One draw is performed for each [`DrawIndirectCommand`] struct in `indirect_buffer`.
1217 /// The maximum number of draw commands in the buffer is limited by the
1218 /// [`max_draw_indirect_count`](crate::device::Properties::max_draw_indirect_count) limit.
1219 /// This limit is 1 unless the
1220 /// [`multi_draw_indirect`](crate::device::Features::multi_draw_indirect) feature has been
1221 /// enabled.
1222 ///
1223 /// `vertex_buffer` is a set of vertex and/or instance buffers used to provide input. It is
1224 /// used for every draw operation.
1225 ///
1226 /// All data in `vertex_buffer` is used for every draw operation. To use only some data in the
1227 /// buffer, wrap it in a `vulkano::buffer::BufferSlice`.
1228 #[inline]
draw_indirect<V, Gp, S, Pc, Inb>( &mut self, pipeline: Gp, dynamic: &DynamicState, vertex_buffers: V, indirect_buffer: Inb, descriptor_sets: S, push_constants: Pc, ) -> Result<&mut Self, DrawIndirectError> where Gp: GraphicsPipelineAbstract + VertexSource<V> + Send + Sync + 'static + Clone, S: DescriptorSetsCollection, Inb: BufferAccess + TypedBufferAccess<Content = [DrawIndirectCommand]> + Send + Sync + 'static,1229 pub fn draw_indirect<V, Gp, S, Pc, Inb>(
1230 &mut self,
1231 pipeline: Gp,
1232 dynamic: &DynamicState,
1233 vertex_buffers: V,
1234 indirect_buffer: Inb,
1235 descriptor_sets: S,
1236 push_constants: Pc,
1237 ) -> Result<&mut Self, DrawIndirectError>
1238 where
1239 Gp: GraphicsPipelineAbstract + VertexSource<V> + Send + Sync + 'static + Clone, // TODO: meh for Clone
1240 S: DescriptorSetsCollection,
1241 Inb: BufferAccess
1242 + TypedBufferAccess<Content = [DrawIndirectCommand]>
1243 + Send
1244 + Sync
1245 + 'static,
1246 {
1247 let descriptor_sets = descriptor_sets.into_vec();
1248
1249 unsafe {
1250 // TODO: must check that pipeline is compatible with render pass
1251
1252 self.ensure_inside_render_pass_inline(&pipeline)?;
1253 check_indirect_buffer(self.device(), &indirect_buffer)?;
1254 check_dynamic_state_validity(&pipeline, dynamic)?;
1255 check_push_constants_validity(pipeline.layout(), &push_constants)?;
1256 check_descriptor_sets_validity(pipeline.layout(), &descriptor_sets)?;
1257 let vb_infos = check_vertex_buffers(&pipeline, vertex_buffers)?;
1258
1259 let requested = indirect_buffer.len() as u32;
1260 let limit = self
1261 .device()
1262 .physical_device()
1263 .properties()
1264 .max_draw_indirect_count;
1265
1266 if requested > limit {
1267 return Err(
1268 CheckIndirectBufferError::MaxDrawIndirectCountLimitExceeded {
1269 limit,
1270 requested,
1271 }
1272 .into(),
1273 );
1274 }
1275
1276 if let StateCacherOutcome::NeedChange =
1277 self.state_cacher.bind_graphics_pipeline(&pipeline)
1278 {
1279 self.inner.bind_pipeline_graphics(pipeline.clone());
1280 }
1281
1282 let dynamic = self.state_cacher.dynamic_state(dynamic);
1283
1284 set_push_constants(&mut self.inner, pipeline.layout(), push_constants);
1285 set_state(&mut self.inner, &dynamic);
1286 bind_descriptor_sets(
1287 &mut self.inner,
1288 &mut self.state_cacher,
1289 PipelineBindPoint::Graphics,
1290 pipeline.layout(),
1291 descriptor_sets,
1292 )?;
1293 bind_vertex_buffers(
1294 &mut self.inner,
1295 &mut self.state_cacher,
1296 vb_infos.vertex_buffers,
1297 )?;
1298
1299 debug_assert!(self.queue_family().supports_graphics());
1300
1301 self.inner.draw_indirect(
1302 indirect_buffer,
1303 requested,
1304 mem::size_of::<DrawIndirectCommand>() as u32,
1305 )?;
1306 Ok(self)
1307 }
1308 }
1309
1310 /// Perform a single draw operation using a graphics pipeline, using an index buffer.
1311 ///
1312 /// `vertex_buffer` is a set of vertex and/or instance buffers used to provide input.
1313 /// `index_buffer` is a buffer containing indices into the vertex buffer that should be
1314 /// processed in order.
1315 ///
1316 /// All data in `vertex_buffer` and `index_buffer` is used for the draw operation. To use
1317 /// only some data in the buffer, wrap it in a `vulkano::buffer::BufferSlice`.
1318 #[inline]
draw_indexed<V, Gp, S, Pc, Ib, I>( &mut self, pipeline: Gp, dynamic: &DynamicState, vertex_buffers: V, index_buffer: Ib, descriptor_sets: S, push_constants: Pc, ) -> Result<&mut Self, DrawIndexedError> where Gp: GraphicsPipelineAbstract + VertexSource<V> + Send + Sync + 'static + Clone, S: DescriptorSetsCollection, Ib: BufferAccess + TypedBufferAccess<Content = [I]> + Send + Sync + 'static, I: Index + 'static,1319 pub fn draw_indexed<V, Gp, S, Pc, Ib, I>(
1320 &mut self,
1321 pipeline: Gp,
1322 dynamic: &DynamicState,
1323 vertex_buffers: V,
1324 index_buffer: Ib,
1325 descriptor_sets: S,
1326 push_constants: Pc,
1327 ) -> Result<&mut Self, DrawIndexedError>
1328 where
1329 Gp: GraphicsPipelineAbstract + VertexSource<V> + Send + Sync + 'static + Clone, // TODO: meh for Clone
1330 S: DescriptorSetsCollection,
1331 Ib: BufferAccess + TypedBufferAccess<Content = [I]> + Send + Sync + 'static,
1332 I: Index + 'static,
1333 {
1334 let descriptor_sets = descriptor_sets.into_vec();
1335
1336 unsafe {
1337 // TODO: must check that pipeline is compatible with render pass
1338
1339 self.ensure_inside_render_pass_inline(&pipeline)?;
1340 let ib_infos = check_index_buffer(self.device(), &index_buffer)?;
1341 check_dynamic_state_validity(&pipeline, dynamic)?;
1342 check_push_constants_validity(pipeline.layout(), &push_constants)?;
1343 check_descriptor_sets_validity(pipeline.layout(), &descriptor_sets)?;
1344 let vb_infos = check_vertex_buffers(&pipeline, vertex_buffers)?;
1345
1346 if let StateCacherOutcome::NeedChange =
1347 self.state_cacher.bind_graphics_pipeline(&pipeline)
1348 {
1349 self.inner.bind_pipeline_graphics(pipeline.clone());
1350 }
1351
1352 if let StateCacherOutcome::NeedChange =
1353 self.state_cacher.bind_index_buffer(&index_buffer, I::ty())
1354 {
1355 self.inner.bind_index_buffer(index_buffer, I::ty())?;
1356 }
1357
1358 let dynamic = self.state_cacher.dynamic_state(dynamic);
1359
1360 set_push_constants(&mut self.inner, pipeline.layout(), push_constants);
1361 set_state(&mut self.inner, &dynamic);
1362 bind_descriptor_sets(
1363 &mut self.inner,
1364 &mut self.state_cacher,
1365 PipelineBindPoint::Graphics,
1366 pipeline.layout(),
1367 descriptor_sets,
1368 )?;
1369 bind_vertex_buffers(
1370 &mut self.inner,
1371 &mut self.state_cacher,
1372 vb_infos.vertex_buffers,
1373 )?;
1374 // TODO: how to handle an index out of range of the vertex buffers?
1375
1376 debug_assert!(self.queue_family().supports_graphics());
1377
1378 self.inner.draw_indexed(
1379 ib_infos.num_indices as u32,
1380 vb_infos.instance_count as u32,
1381 0,
1382 0,
1383 0,
1384 );
1385 Ok(self)
1386 }
1387 }
1388
1389 /// Perform multiple draw operations using a graphics pipeline, using an index buffer.
1390 ///
1391 /// One draw is performed for each [`DrawIndirectCommand`] struct in `indirect_buffer`.
1392 /// The maximum number of draw commands in the buffer is limited by the
1393 /// [`max_draw_indirect_count`](crate::device::Properties::max_draw_indirect_count) limit.
1394 /// This limit is 1 unless the
1395 /// [`multi_draw_indirect`](crate::device::Features::multi_draw_indirect) feature has been
1396 /// enabled.
1397 ///
1398 /// `vertex_buffer` is a set of vertex and/or instance buffers used to provide input.
1399 /// `index_buffer` is a buffer containing indices into the vertex buffer that should be
1400 /// processed in order.
1401 ///
1402 /// All data in `vertex_buffer` and `index_buffer` is used for every draw operation. To use
1403 /// only some data in the buffer, wrap it in a `vulkano::buffer::BufferSlice`.
1404 #[inline]
draw_indexed_indirect<V, Gp, S, Pc, Ib, Inb, I>( &mut self, pipeline: Gp, dynamic: &DynamicState, vertex_buffers: V, index_buffer: Ib, indirect_buffer: Inb, descriptor_sets: S, push_constants: Pc, ) -> Result<&mut Self, DrawIndexedIndirectError> where Gp: GraphicsPipelineAbstract + VertexSource<V> + Send + Sync + 'static + Clone, S: DescriptorSetsCollection, Ib: BufferAccess + TypedBufferAccess<Content = [I]> + Send + Sync + 'static, Inb: BufferAccess + TypedBufferAccess<Content = [DrawIndexedIndirectCommand]> + Send + Sync + 'static, I: Index + 'static,1405 pub fn draw_indexed_indirect<V, Gp, S, Pc, Ib, Inb, I>(
1406 &mut self,
1407 pipeline: Gp,
1408 dynamic: &DynamicState,
1409 vertex_buffers: V,
1410 index_buffer: Ib,
1411 indirect_buffer: Inb,
1412 descriptor_sets: S,
1413 push_constants: Pc,
1414 ) -> Result<&mut Self, DrawIndexedIndirectError>
1415 where
1416 Gp: GraphicsPipelineAbstract + VertexSource<V> + Send + Sync + 'static + Clone, // TODO: meh for Clone
1417 S: DescriptorSetsCollection,
1418 Ib: BufferAccess + TypedBufferAccess<Content = [I]> + Send + Sync + 'static,
1419 Inb: BufferAccess
1420 + TypedBufferAccess<Content = [DrawIndexedIndirectCommand]>
1421 + Send
1422 + Sync
1423 + 'static,
1424 I: Index + 'static,
1425 {
1426 let descriptor_sets = descriptor_sets.into_vec();
1427
1428 unsafe {
1429 // TODO: must check that pipeline is compatible with render pass
1430
1431 self.ensure_inside_render_pass_inline(&pipeline)?;
1432 let ib_infos = check_index_buffer(self.device(), &index_buffer)?;
1433 check_indirect_buffer(self.device(), &indirect_buffer)?;
1434 check_dynamic_state_validity(&pipeline, dynamic)?;
1435 check_push_constants_validity(pipeline.layout(), &push_constants)?;
1436 check_descriptor_sets_validity(pipeline.layout(), &descriptor_sets)?;
1437 let vb_infos = check_vertex_buffers(&pipeline, vertex_buffers)?;
1438
1439 let requested = indirect_buffer.len() as u32;
1440 let limit = self
1441 .device()
1442 .physical_device()
1443 .properties()
1444 .max_draw_indirect_count;
1445
1446 if requested > limit {
1447 return Err(
1448 CheckIndirectBufferError::MaxDrawIndirectCountLimitExceeded {
1449 limit,
1450 requested,
1451 }
1452 .into(),
1453 );
1454 }
1455
1456 if let StateCacherOutcome::NeedChange =
1457 self.state_cacher.bind_graphics_pipeline(&pipeline)
1458 {
1459 self.inner.bind_pipeline_graphics(pipeline.clone());
1460 }
1461
1462 if let StateCacherOutcome::NeedChange =
1463 self.state_cacher.bind_index_buffer(&index_buffer, I::ty())
1464 {
1465 self.inner.bind_index_buffer(index_buffer, I::ty())?;
1466 }
1467
1468 let dynamic = self.state_cacher.dynamic_state(dynamic);
1469
1470 set_push_constants(&mut self.inner, pipeline.layout(), push_constants);
1471 set_state(&mut self.inner, &dynamic);
1472 bind_descriptor_sets(
1473 &mut self.inner,
1474 &mut self.state_cacher,
1475 PipelineBindPoint::Graphics,
1476 pipeline.layout(),
1477 descriptor_sets,
1478 )?;
1479 bind_vertex_buffers(
1480 &mut self.inner,
1481 &mut self.state_cacher,
1482 vb_infos.vertex_buffers,
1483 )?;
1484
1485 debug_assert!(self.queue_family().supports_graphics());
1486
1487 self.inner.draw_indexed_indirect(
1488 indirect_buffer,
1489 requested,
1490 mem::size_of::<DrawIndexedIndirectCommand>() as u32,
1491 )?;
1492 Ok(self)
1493 }
1494 }
1495
1496 /// Adds a command that writes the content of a buffer.
1497 ///
1498 /// This function is similar to the `memset` function in C. The `data` parameter is a number
1499 /// that will be repeatedly written through the entire buffer.
1500 ///
1501 /// > **Note**: This function is technically safe because buffers can only contain integers or
1502 /// > floating point numbers, which are always valid whatever their memory representation is.
1503 /// > But unless your buffer actually contains only 32-bits integers, you are encouraged to use
1504 /// > this function only for zeroing the content of a buffer by passing `0` for the data.
1505 // TODO: not safe because of signalling NaNs
1506 #[inline]
fill_buffer<B>(&mut self, buffer: B, data: u32) -> Result<&mut Self, FillBufferError> where B: BufferAccess + Send + Sync + 'static,1507 pub fn fill_buffer<B>(&mut self, buffer: B, data: u32) -> Result<&mut Self, FillBufferError>
1508 where
1509 B: BufferAccess + Send + Sync + 'static,
1510 {
1511 unsafe {
1512 self.ensure_outside_render_pass()?;
1513 check_fill_buffer(self.device(), &buffer)?;
1514 self.inner.fill_buffer(buffer, data);
1515 Ok(self)
1516 }
1517 }
1518
1519 /// Adds a command that writes data to a buffer.
1520 ///
1521 /// If `data` is larger than the buffer, only the part of `data` that fits is written. If the
1522 /// buffer is larger than `data`, only the start of the buffer is written.
1523 #[inline]
update_buffer<B, D, Dd>( &mut self, buffer: B, data: Dd, ) -> Result<&mut Self, UpdateBufferError> where B: TypedBufferAccess<Content = D> + Send + Sync + 'static, D: ?Sized, Dd: SafeDeref<Target = D> + Send + Sync + 'static,1524 pub fn update_buffer<B, D, Dd>(
1525 &mut self,
1526 buffer: B,
1527 data: Dd,
1528 ) -> Result<&mut Self, UpdateBufferError>
1529 where
1530 B: TypedBufferAccess<Content = D> + Send + Sync + 'static,
1531 D: ?Sized,
1532 Dd: SafeDeref<Target = D> + Send + Sync + 'static,
1533 {
1534 unsafe {
1535 self.ensure_outside_render_pass()?;
1536 check_update_buffer(self.device(), &buffer, data.deref())?;
1537
1538 let size_of_data = mem::size_of_val(data.deref()) as DeviceSize;
1539 if buffer.size() >= size_of_data {
1540 self.inner.update_buffer(buffer, data);
1541 } else {
1542 unimplemented!() // TODO:
1543 //self.inner.update_buffer(buffer.slice(0 .. size_of_data), data);
1544 }
1545
1546 Ok(self)
1547 }
1548 }
1549
1550 /// Adds a command that begins a query.
1551 ///
1552 /// The query will be active until [`end_query`](Self::end_query) is called for the same query.
1553 ///
1554 /// # Safety
1555 /// The query must be unavailable, ensured by calling [`reset_query_pool`](Self::reset_query_pool).
begin_query( &mut self, query_pool: Arc<QueryPool>, query: u32, flags: QueryControlFlags, ) -> Result<&mut Self, BeginQueryError>1556 pub unsafe fn begin_query(
1557 &mut self,
1558 query_pool: Arc<QueryPool>,
1559 query: u32,
1560 flags: QueryControlFlags,
1561 ) -> Result<&mut Self, BeginQueryError> {
1562 check_begin_query(self.device(), &query_pool, query, flags)?;
1563
1564 match query_pool.ty() {
1565 QueryType::Occlusion => {
1566 if !self.queue_family().supports_graphics() {
1567 return Err(
1568 AutoCommandBufferBuilderContextError::NotSupportedByQueueFamily.into(),
1569 );
1570 }
1571 }
1572 QueryType::PipelineStatistics(flags) => {
1573 if flags.is_compute() && !self.queue_family().supports_compute()
1574 || flags.is_graphics() && !self.queue_family().supports_graphics()
1575 {
1576 return Err(
1577 AutoCommandBufferBuilderContextError::NotSupportedByQueueFamily.into(),
1578 );
1579 }
1580 }
1581 QueryType::Timestamp => unreachable!(),
1582 }
1583
1584 let ty = query_pool.ty();
1585 let raw_ty = ty.into();
1586 let raw_query_pool = query_pool.internal_object();
1587 if self.query_state.contains_key(&raw_ty) {
1588 return Err(AutoCommandBufferBuilderContextError::QueryIsActive.into());
1589 }
1590
1591 // TODO: validity checks
1592 self.inner.begin_query(query_pool, query, flags);
1593 self.query_state.insert(
1594 raw_ty,
1595 QueryState {
1596 query_pool: raw_query_pool,
1597 query,
1598 ty,
1599 flags,
1600 in_subpass: self.render_pass_state.is_some(),
1601 },
1602 );
1603
1604 Ok(self)
1605 }
1606
1607 /// Adds a command that ends an active query.
end_query( &mut self, query_pool: Arc<QueryPool>, query: u32, ) -> Result<&mut Self, EndQueryError>1608 pub fn end_query(
1609 &mut self,
1610 query_pool: Arc<QueryPool>,
1611 query: u32,
1612 ) -> Result<&mut Self, EndQueryError> {
1613 unsafe {
1614 check_end_query(self.device(), &query_pool, query)?;
1615
1616 let raw_ty = query_pool.ty().into();
1617 let raw_query_pool = query_pool.internal_object();
1618 if !self.query_state.get(&raw_ty).map_or(false, |state| {
1619 state.query_pool == raw_query_pool && state.query == query
1620 }) {
1621 return Err(AutoCommandBufferBuilderContextError::QueryNotActive.into());
1622 }
1623
1624 self.inner.end_query(query_pool, query);
1625 self.query_state.remove(&raw_ty);
1626 }
1627
1628 Ok(self)
1629 }
1630
1631 /// Adds a command that writes a timestamp to a timestamp query.
1632 ///
1633 /// # Safety
1634 /// The query must be unavailable, ensured by calling [`reset_query_pool`](Self::reset_query_pool).
write_timestamp( &mut self, query_pool: Arc<QueryPool>, query: u32, stage: PipelineStage, ) -> Result<&mut Self, WriteTimestampError>1635 pub unsafe fn write_timestamp(
1636 &mut self,
1637 query_pool: Arc<QueryPool>,
1638 query: u32,
1639 stage: PipelineStage,
1640 ) -> Result<&mut Self, WriteTimestampError> {
1641 check_write_timestamp(
1642 self.device(),
1643 self.queue_family(),
1644 &query_pool,
1645 query,
1646 stage,
1647 )?;
1648
1649 if !(self.queue_family().supports_graphics()
1650 || self.queue_family().supports_compute()
1651 || self.queue_family().explicitly_supports_transfers())
1652 {
1653 return Err(AutoCommandBufferBuilderContextError::NotSupportedByQueueFamily.into());
1654 }
1655
1656 // TODO: validity checks
1657 self.inner.write_timestamp(query_pool, query, stage);
1658
1659 Ok(self)
1660 }
1661
1662 /// Adds a command that copies the results of a range of queries to a buffer on the GPU.
1663 ///
1664 /// [`query_pool.ty().result_size()`](crate::query::QueryType::result_size) elements
1665 /// will be written for each query in the range, plus 1 extra element per query if
1666 /// [`QueryResultFlags::with_availability`] is enabled.
1667 /// The provided buffer must be large enough to hold the data.
1668 ///
1669 /// See also [`get_results`](crate::query::QueriesRange::get_results).
copy_query_pool_results<D, T>( &mut self, query_pool: Arc<QueryPool>, queries: Range<u32>, destination: D, flags: QueryResultFlags, ) -> Result<&mut Self, CopyQueryPoolResultsError> where D: BufferAccess + TypedBufferAccess<Content = [T]> + Send + Sync + 'static, T: QueryResultElement,1670 pub fn copy_query_pool_results<D, T>(
1671 &mut self,
1672 query_pool: Arc<QueryPool>,
1673 queries: Range<u32>,
1674 destination: D,
1675 flags: QueryResultFlags,
1676 ) -> Result<&mut Self, CopyQueryPoolResultsError>
1677 where
1678 D: BufferAccess + TypedBufferAccess<Content = [T]> + Send + Sync + 'static,
1679 T: QueryResultElement,
1680 {
1681 unsafe {
1682 self.ensure_outside_render_pass()?;
1683 let stride = check_copy_query_pool_results(
1684 self.device(),
1685 &query_pool,
1686 queries.clone(),
1687 &destination,
1688 flags,
1689 )?;
1690 self.inner
1691 .copy_query_pool_results(query_pool, queries, destination, stride, flags)?;
1692 }
1693
1694 Ok(self)
1695 }
1696
1697 /// Adds a command to reset a range of queries on a query pool.
1698 ///
1699 /// The affected queries will be marked as "unavailable" after this command runs, and will no
1700 /// longer return any results. They will be ready to have new results recorded for them.
1701 ///
1702 /// # Safety
1703 /// The queries in the specified range must not be active in another command buffer.
reset_query_pool( &mut self, query_pool: Arc<QueryPool>, queries: Range<u32>, ) -> Result<&mut Self, ResetQueryPoolError>1704 pub unsafe fn reset_query_pool(
1705 &mut self,
1706 query_pool: Arc<QueryPool>,
1707 queries: Range<u32>,
1708 ) -> Result<&mut Self, ResetQueryPoolError> {
1709 self.ensure_outside_render_pass()?;
1710 check_reset_query_pool(self.device(), &query_pool, queries.clone())?;
1711
1712 let raw_query_pool = query_pool.internal_object();
1713 if self
1714 .query_state
1715 .values()
1716 .any(|state| state.query_pool == raw_query_pool && queries.contains(&state.query))
1717 {
1718 return Err(AutoCommandBufferBuilderContextError::QueryIsActive.into());
1719 }
1720
1721 // TODO: validity checks
1722 // Do other command buffers actually matter here? Not sure on the Vulkan spec.
1723 self.inner.reset_query_pool(query_pool, queries);
1724
1725 Ok(self)
1726 }
1727 }
1728
1729 /// Commands that can only be executed on primary command buffers
1730 impl<P> AutoCommandBufferBuilder<PrimaryAutoCommandBuffer<P::Alloc>, P>
1731 where
1732 P: CommandPoolBuilderAlloc,
1733 {
1734 /// Adds a command that enters a render pass.
1735 ///
1736 /// If `contents` is `SubpassContents::SecondaryCommandBuffers`, then you will only be able to
1737 /// add secondary command buffers while you're inside the first subpass of the render pass.
1738 /// If it is `SubpassContents::Inline`, you will only be able to add inline draw commands and
1739 /// not secondary command buffers.
1740 ///
1741 /// C must contain exactly one clear value for each attachment in the framebuffer.
1742 ///
1743 /// You must call this before you can add draw commands.
1744 #[inline]
begin_render_pass<F, I>( &mut self, framebuffer: F, contents: SubpassContents, clear_values: I, ) -> Result<&mut Self, BeginRenderPassError> where F: FramebufferAbstract + Clone + Send + Sync + 'static, I: IntoIterator<Item = ClearValue>,1745 pub fn begin_render_pass<F, I>(
1746 &mut self,
1747 framebuffer: F,
1748 contents: SubpassContents,
1749 clear_values: I,
1750 ) -> Result<&mut Self, BeginRenderPassError>
1751 where
1752 F: FramebufferAbstract + Clone + Send + Sync + 'static,
1753 I: IntoIterator<Item = ClearValue>,
1754 {
1755 unsafe {
1756 if !self.queue_family().supports_graphics() {
1757 return Err(AutoCommandBufferBuilderContextError::NotSupportedByQueueFamily.into());
1758 }
1759
1760 self.ensure_outside_render_pass()?;
1761
1762 let clear_values = framebuffer
1763 .render_pass()
1764 .desc()
1765 .convert_clear_values(clear_values);
1766 let clear_values = clear_values.collect::<Vec<_>>().into_iter(); // TODO: necessary for Send + Sync ; needs an API rework of convert_clear_values
1767 let mut clear_values_copy = clear_values.clone().enumerate(); // TODO: Proper errors for clear value errors instead of panics
1768
1769 for (atch_i, atch_desc) in framebuffer
1770 .render_pass()
1771 .desc()
1772 .attachments()
1773 .into_iter()
1774 .enumerate()
1775 {
1776 match clear_values_copy.next() {
1777 Some((clear_i, clear_value)) => {
1778 if atch_desc.load == LoadOp::Clear {
1779 match clear_value {
1780 ClearValue::None => panic!("Bad ClearValue! index: {}, attachment index: {}, expected: {:?}, got: None",
1781 clear_i, atch_i, atch_desc.format.ty()),
1782 ClearValue::Float(_) => if atch_desc.format.ty() != FormatTy::Float {
1783 panic!("Bad ClearValue! index: {}, attachment index: {}, expected: {:?}, got: Float",
1784 clear_i, atch_i, atch_desc.format.ty());
1785 }
1786 ClearValue::Int(_) => if atch_desc.format.ty() != FormatTy::Sint {
1787 panic!("Bad ClearValue! index: {}, attachment index: {}, expected: {:?}, got: Int",
1788 clear_i, atch_i, atch_desc.format.ty());
1789 }
1790 ClearValue::Uint(_) => if atch_desc.format.ty() != FormatTy::Uint {
1791 panic!("Bad ClearValue! index: {}, attachment index: {}, expected: {:?}, got: Uint",
1792 clear_i, atch_i, atch_desc.format.ty());
1793 }
1794 ClearValue::Depth(_) => if atch_desc.format.ty() != FormatTy::Depth {
1795 panic!("Bad ClearValue! index: {}, attachment index: {}, expected: {:?}, got: Depth",
1796 clear_i, atch_i, atch_desc.format.ty());
1797 }
1798 ClearValue::Stencil(_) => if atch_desc.format.ty() != FormatTy::Stencil {
1799 panic!("Bad ClearValue! index: {}, attachment index: {}, expected: {:?}, got: Stencil",
1800 clear_i, atch_i, atch_desc.format.ty());
1801 }
1802 ClearValue::DepthStencil(_) => if atch_desc.format.ty() != FormatTy::DepthStencil {
1803 panic!("Bad ClearValue! index: {}, attachment index: {}, expected: {:?}, got: DepthStencil",
1804 clear_i, atch_i, atch_desc.format.ty());
1805 }
1806 }
1807 } else {
1808 if clear_value != ClearValue::None {
1809 panic!("Bad ClearValue! index: {}, attachment index: {}, expected: None, got: {:?}",
1810 clear_i, atch_i, clear_value);
1811 }
1812 }
1813 }
1814 None => panic!("Not enough clear values"),
1815 }
1816 }
1817
1818 if clear_values_copy.count() != 0 {
1819 panic!("Too many clear values")
1820 }
1821
1822 if let Some(multiview_desc) = framebuffer.render_pass().desc().multiview() {
1823 // When multiview is enabled, at the beginning of each subpass all non-render pass state is undefined
1824 self.state_cacher.invalidate();
1825
1826 // ensure that the framebuffer is compatible with the render pass multiview configuration
1827 if multiview_desc
1828 .view_masks
1829 .iter()
1830 .chain(multiview_desc.correlation_masks.iter())
1831 .map(|&mask| 32 - mask.leading_zeros()) // calculates the highest used layer index of the mask
1832 .any(|highest_used_layer| highest_used_layer > framebuffer.layers())
1833 {
1834 panic!("A multiview mask references more layers than exist in the framebuffer");
1835 }
1836 }
1837
1838 let framebuffer_object = FramebufferAbstract::inner(&framebuffer).internal_object();
1839 self.inner
1840 .begin_render_pass(framebuffer.clone(), contents, clear_values)?;
1841 self.render_pass_state = Some(RenderPassState {
1842 subpass: (framebuffer.render_pass().clone(), 0),
1843 contents,
1844 framebuffer: framebuffer_object,
1845 });
1846 Ok(self)
1847 }
1848 }
1849
1850 /// Adds a command that ends the current render pass.
1851 ///
1852 /// This must be called after you went through all the subpasses and before you can build
1853 /// the command buffer or add further commands.
1854 #[inline]
end_render_pass(&mut self) -> Result<&mut Self, AutoCommandBufferBuilderContextError>1855 pub fn end_render_pass(&mut self) -> Result<&mut Self, AutoCommandBufferBuilderContextError> {
1856 unsafe {
1857 if let Some(render_pass_state) = self.render_pass_state.as_ref() {
1858 let (ref rp, index) = render_pass_state.subpass;
1859
1860 if rp.desc().subpasses().len() as u32 != index + 1 {
1861 return Err(AutoCommandBufferBuilderContextError::NumSubpassesMismatch {
1862 actual: rp.desc().subpasses().len() as u32,
1863 current: index,
1864 });
1865 }
1866 } else {
1867 return Err(AutoCommandBufferBuilderContextError::ForbiddenOutsideRenderPass);
1868 }
1869
1870 if self.query_state.values().any(|state| state.in_subpass) {
1871 return Err(AutoCommandBufferBuilderContextError::QueryIsActive);
1872 }
1873
1874 debug_assert!(self.queue_family().supports_graphics());
1875
1876 self.inner.end_render_pass();
1877 self.render_pass_state = None;
1878 Ok(self)
1879 }
1880 }
1881
1882 /// Adds a command that executes a secondary command buffer.
1883 ///
1884 /// If the `flags` that `command_buffer` was created with are more restrictive than those of
1885 /// `self`, then `self` will be restricted to match. E.g. executing a secondary command buffer
1886 /// with `Flags::OneTimeSubmit` will set `self`'s flags to `Flags::OneTimeSubmit` also.
execute_commands<C>( &mut self, command_buffer: C, ) -> Result<&mut Self, ExecuteCommandsError> where C: SecondaryCommandBuffer + Send + Sync + 'static,1887 pub fn execute_commands<C>(
1888 &mut self,
1889 command_buffer: C,
1890 ) -> Result<&mut Self, ExecuteCommandsError>
1891 where
1892 C: SecondaryCommandBuffer + Send + Sync + 'static,
1893 {
1894 self.check_command_buffer(&command_buffer)?;
1895 let secondary_usage = command_buffer.inner().usage();
1896
1897 unsafe {
1898 let mut builder = self.inner.execute_commands();
1899 builder.add(command_buffer);
1900 builder.submit()?;
1901 }
1902
1903 // Secondary command buffer could leave the primary in any state.
1904 self.state_cacher.invalidate();
1905
1906 // If the secondary is non-concurrent or one-time use, that restricts the primary as well.
1907 self.usage = std::cmp::min(self.usage, secondary_usage);
1908
1909 Ok(self)
1910 }
1911
1912 /// Adds a command that multiple secondary command buffers in a vector.
1913 ///
1914 /// This requires that the secondary command buffers do not have resource conflicts; an error
1915 /// will be returned if there are any. Use `execute_commands` if you want to ensure that
1916 /// resource conflicts are automatically resolved.
1917 // TODO ^ would be nice if this just worked without errors
execute_commands_from_vec<C>( &mut self, command_buffers: Vec<C>, ) -> Result<&mut Self, ExecuteCommandsError> where C: SecondaryCommandBuffer + Send + Sync + 'static,1918 pub fn execute_commands_from_vec<C>(
1919 &mut self,
1920 command_buffers: Vec<C>,
1921 ) -> Result<&mut Self, ExecuteCommandsError>
1922 where
1923 C: SecondaryCommandBuffer + Send + Sync + 'static,
1924 {
1925 for command_buffer in &command_buffers {
1926 self.check_command_buffer(command_buffer)?;
1927 }
1928
1929 let mut secondary_usage = CommandBufferUsage::SimultaneousUse; // Most permissive usage
1930 unsafe {
1931 let mut builder = self.inner.execute_commands();
1932 for command_buffer in command_buffers {
1933 secondary_usage = std::cmp::min(secondary_usage, command_buffer.inner().usage());
1934 builder.add(command_buffer);
1935 }
1936 builder.submit()?;
1937 }
1938
1939 // Secondary command buffer could leave the primary in any state.
1940 self.state_cacher.invalidate();
1941
1942 // If the secondary is non-concurrent or one-time use, that restricts the primary as well.
1943 self.usage = std::cmp::min(self.usage, secondary_usage);
1944
1945 Ok(self)
1946 }
1947
1948 // Helper function for execute_commands
check_command_buffer<C>( &self, command_buffer: &C, ) -> Result<(), AutoCommandBufferBuilderContextError> where C: SecondaryCommandBuffer + Send + Sync + 'static,1949 fn check_command_buffer<C>(
1950 &self,
1951 command_buffer: &C,
1952 ) -> Result<(), AutoCommandBufferBuilderContextError>
1953 where
1954 C: SecondaryCommandBuffer + Send + Sync + 'static,
1955 {
1956 if let Some(render_pass) = command_buffer.inheritance().render_pass {
1957 self.ensure_inside_render_pass_secondary(&render_pass)?;
1958 } else {
1959 self.ensure_outside_render_pass()?;
1960 }
1961
1962 for state in self.query_state.values() {
1963 match state.ty {
1964 QueryType::Occlusion => match command_buffer.inheritance().occlusion_query {
1965 Some(inherited_flags) => {
1966 let inherited_flags = ash::vk::QueryControlFlags::from(inherited_flags);
1967 let state_flags = ash::vk::QueryControlFlags::from(state.flags);
1968
1969 if inherited_flags & state_flags != state_flags {
1970 return Err(AutoCommandBufferBuilderContextError::QueryNotInherited);
1971 }
1972 }
1973 None => return Err(AutoCommandBufferBuilderContextError::QueryNotInherited),
1974 },
1975 QueryType::PipelineStatistics(state_flags) => {
1976 let inherited_flags = command_buffer.inheritance().query_statistics_flags;
1977 let inherited_flags =
1978 ash::vk::QueryPipelineStatisticFlags::from(inherited_flags);
1979 let state_flags = ash::vk::QueryPipelineStatisticFlags::from(state_flags);
1980
1981 if inherited_flags & state_flags != state_flags {
1982 return Err(AutoCommandBufferBuilderContextError::QueryNotInherited);
1983 }
1984 }
1985 _ => (),
1986 }
1987 }
1988
1989 Ok(())
1990 }
1991
1992 #[inline]
ensure_inside_render_pass_secondary( &self, render_pass: &CommandBufferInheritanceRenderPass<&dyn FramebufferAbstract>, ) -> Result<(), AutoCommandBufferBuilderContextError>1993 fn ensure_inside_render_pass_secondary(
1994 &self,
1995 render_pass: &CommandBufferInheritanceRenderPass<&dyn FramebufferAbstract>,
1996 ) -> Result<(), AutoCommandBufferBuilderContextError> {
1997 let render_pass_state = self
1998 .render_pass_state
1999 .as_ref()
2000 .ok_or(AutoCommandBufferBuilderContextError::ForbiddenOutsideRenderPass)?;
2001
2002 if render_pass_state.contents != SubpassContents::SecondaryCommandBuffers {
2003 return Err(AutoCommandBufferBuilderContextError::WrongSubpassType);
2004 }
2005
2006 // Subpasses must be the same.
2007 if render_pass.subpass.index() != render_pass_state.subpass.1 {
2008 return Err(AutoCommandBufferBuilderContextError::WrongSubpassIndex);
2009 }
2010
2011 // Render passes must be compatible.
2012 if !render_pass
2013 .subpass
2014 .render_pass()
2015 .desc()
2016 .is_compatible_with_desc(render_pass_state.subpass.0.desc())
2017 {
2018 return Err(AutoCommandBufferBuilderContextError::IncompatibleRenderPass);
2019 }
2020
2021 // Framebuffer, if present on the secondary command buffer, must be the
2022 // same as the one in the current render pass.
2023 if let Some(framebuffer) = render_pass.framebuffer {
2024 if FramebufferAbstract::inner(framebuffer).internal_object()
2025 != render_pass_state.framebuffer
2026 {
2027 return Err(AutoCommandBufferBuilderContextError::IncompatibleFramebuffer);
2028 }
2029 }
2030
2031 Ok(())
2032 }
2033
2034 /// Adds a command that jumps to the next subpass of the current render pass.
2035 #[inline]
next_subpass( &mut self, contents: SubpassContents, ) -> Result<&mut Self, AutoCommandBufferBuilderContextError>2036 pub fn next_subpass(
2037 &mut self,
2038 contents: SubpassContents,
2039 ) -> Result<&mut Self, AutoCommandBufferBuilderContextError> {
2040 unsafe {
2041 if let Some(render_pass_state) = self.render_pass_state.as_mut() {
2042 let (ref rp, ref mut index) = render_pass_state.subpass;
2043
2044 if *index + 1 >= rp.desc().subpasses().len() as u32 {
2045 return Err(AutoCommandBufferBuilderContextError::NumSubpassesMismatch {
2046 actual: rp.desc().subpasses().len() as u32,
2047 current: *index,
2048 });
2049 } else {
2050 *index += 1;
2051 render_pass_state.contents = contents;
2052 }
2053
2054 if let Some(multiview) = rp.desc().multiview() {
2055 // When multiview is enabled, at the beginning of each subpass all non-render pass state is undefined
2056 self.state_cacher.invalidate();
2057 }
2058 } else {
2059 return Err(AutoCommandBufferBuilderContextError::ForbiddenOutsideRenderPass);
2060 }
2061
2062 if self.query_state.values().any(|state| state.in_subpass) {
2063 return Err(AutoCommandBufferBuilderContextError::QueryIsActive);
2064 }
2065
2066 debug_assert!(self.queue_family().supports_graphics());
2067
2068 self.inner.next_subpass(contents);
2069 Ok(self)
2070 }
2071 }
2072 }
2073
2074 impl<P> AutoCommandBufferBuilder<SecondaryAutoCommandBuffer<P::Alloc>, P> where
2075 P: CommandPoolBuilderAlloc
2076 {
2077 }
2078
2079 unsafe impl<L, P> DeviceOwned for AutoCommandBufferBuilder<L, P> {
2080 #[inline]
device(&self) -> &Arc<Device>2081 fn device(&self) -> &Arc<Device> {
2082 self.inner.device()
2083 }
2084 }
2085
2086 // Shortcut function to set the push constants.
set_push_constants<Pc>( destination: &mut SyncCommandBufferBuilder, pipeline_layout: &Arc<PipelineLayout>, push_constants: Pc, )2087 unsafe fn set_push_constants<Pc>(
2088 destination: &mut SyncCommandBufferBuilder,
2089 pipeline_layout: &Arc<PipelineLayout>,
2090 push_constants: Pc,
2091 ) {
2092 for range in pipeline_layout.push_constant_ranges() {
2093 debug_assert_eq!(range.offset % 4, 0);
2094 debug_assert_eq!(range.size % 4, 0);
2095
2096 let data = slice::from_raw_parts(
2097 (&push_constants as *const Pc as *const u8).offset(range.offset as isize),
2098 range.size as usize,
2099 );
2100
2101 destination.push_constants::<[u8]>(
2102 pipeline_layout.clone(),
2103 range.stages,
2104 range.offset as u32,
2105 range.size as u32,
2106 data,
2107 );
2108 }
2109 }
2110
2111 // Shortcut function to change the state of the pipeline.
set_state(destination: &mut SyncCommandBufferBuilder, dynamic: &DynamicState)2112 unsafe fn set_state(destination: &mut SyncCommandBufferBuilder, dynamic: &DynamicState) {
2113 if let Some(line_width) = dynamic.line_width {
2114 destination.set_line_width(line_width);
2115 }
2116
2117 if let Some(ref viewports) = dynamic.viewports {
2118 destination.set_viewport(0, viewports.iter().cloned().collect::<Vec<_>>().into_iter());
2119 // TODO: don't collect
2120 }
2121
2122 if let Some(ref scissors) = dynamic.scissors {
2123 destination.set_scissor(0, scissors.iter().cloned().collect::<Vec<_>>().into_iter());
2124 // TODO: don't collect
2125 }
2126
2127 if let Some(compare_mask) = dynamic.compare_mask {
2128 destination.set_stencil_compare_mask(StencilFaces::Front, compare_mask.front);
2129 destination.set_stencil_compare_mask(StencilFaces::Back, compare_mask.back);
2130 }
2131
2132 if let Some(write_mask) = dynamic.write_mask {
2133 destination.set_stencil_write_mask(StencilFaces::Front, write_mask.front);
2134 destination.set_stencil_write_mask(StencilFaces::Back, write_mask.back);
2135 }
2136
2137 if let Some(reference) = dynamic.reference {
2138 destination.set_stencil_reference(StencilFaces::Front, reference.front);
2139 destination.set_stencil_reference(StencilFaces::Back, reference.back);
2140 }
2141 }
2142
2143 // Shortcut function to bind vertex buffers.
bind_vertex_buffers( destination: &mut SyncCommandBufferBuilder, state_cacher: &mut StateCacher, vertex_buffers: Vec<Box<dyn BufferAccess + Send + Sync>>, ) -> Result<(), SyncCommandBufferBuilderError>2144 unsafe fn bind_vertex_buffers(
2145 destination: &mut SyncCommandBufferBuilder,
2146 state_cacher: &mut StateCacher,
2147 vertex_buffers: Vec<Box<dyn BufferAccess + Send + Sync>>,
2148 ) -> Result<(), SyncCommandBufferBuilderError> {
2149 let binding_range = {
2150 let mut compare = state_cacher.bind_vertex_buffers();
2151 for vb in vertex_buffers.iter() {
2152 compare.add(vb);
2153 }
2154 match compare.compare() {
2155 Some(r) => r,
2156 None => return Ok(()),
2157 }
2158 };
2159
2160 let first_binding = binding_range.start;
2161 let num_bindings = binding_range.end - binding_range.start;
2162
2163 let mut binder = destination.bind_vertex_buffers();
2164 for vb in vertex_buffers
2165 .into_iter()
2166 .skip(first_binding as usize)
2167 .take(num_bindings as usize)
2168 {
2169 binder.add(vb);
2170 }
2171 binder.submit(first_binding)?;
2172 Ok(())
2173 }
2174
bind_descriptor_sets( destination: &mut SyncCommandBufferBuilder, state_cacher: &mut StateCacher, pipeline_bind_point: PipelineBindPoint, pipeline_layout: &Arc<PipelineLayout>, descriptor_sets: Vec<DescriptorSetWithOffsets>, ) -> Result<(), SyncCommandBufferBuilderError>2175 unsafe fn bind_descriptor_sets(
2176 destination: &mut SyncCommandBufferBuilder,
2177 state_cacher: &mut StateCacher,
2178 pipeline_bind_point: PipelineBindPoint,
2179 pipeline_layout: &Arc<PipelineLayout>,
2180 descriptor_sets: Vec<DescriptorSetWithOffsets>,
2181 ) -> Result<(), SyncCommandBufferBuilderError> {
2182 let first_binding = {
2183 let mut compare = state_cacher.bind_descriptor_sets(pipeline_bind_point);
2184 for descriptor_set in descriptor_sets.iter() {
2185 compare.add(descriptor_set);
2186 }
2187 compare.compare()
2188 };
2189
2190 let first_binding = match first_binding {
2191 None => return Ok(()),
2192 Some(fb) => fb,
2193 };
2194
2195 let mut sets_binder = destination.bind_descriptor_sets();
2196 for set in descriptor_sets.into_iter().skip(first_binding as usize) {
2197 sets_binder.add(set);
2198 }
2199 sets_binder.submit(pipeline_bind_point, pipeline_layout.clone(), first_binding)?;
2200 Ok(())
2201 }
2202
2203 pub struct PrimaryAutoCommandBuffer<P = StandardCommandPoolAlloc> {
2204 inner: SyncCommandBuffer,
2205 pool_alloc: P, // Safety: must be dropped after `inner`
2206
2207 // Tracks usage of the command buffer on the GPU.
2208 submit_state: SubmitState,
2209 }
2210
2211 unsafe impl<P> DeviceOwned for PrimaryAutoCommandBuffer<P> {
2212 #[inline]
device(&self) -> &Arc<Device>2213 fn device(&self) -> &Arc<Device> {
2214 self.inner.device()
2215 }
2216 }
2217
2218 unsafe impl<P> PrimaryCommandBuffer for PrimaryAutoCommandBuffer<P> {
2219 #[inline]
inner(&self) -> &UnsafeCommandBuffer2220 fn inner(&self) -> &UnsafeCommandBuffer {
2221 self.inner.as_ref()
2222 }
2223
2224 #[inline]
lock_submit( &self, future: &dyn GpuFuture, queue: &Queue, ) -> Result<(), CommandBufferExecError>2225 fn lock_submit(
2226 &self,
2227 future: &dyn GpuFuture,
2228 queue: &Queue,
2229 ) -> Result<(), CommandBufferExecError> {
2230 match self.submit_state {
2231 SubmitState::OneTime {
2232 ref already_submitted,
2233 } => {
2234 let was_already_submitted = already_submitted.swap(true, Ordering::SeqCst);
2235 if was_already_submitted {
2236 return Err(CommandBufferExecError::OneTimeSubmitAlreadySubmitted);
2237 }
2238 }
2239 SubmitState::ExclusiveUse { ref in_use } => {
2240 let already_in_use = in_use.swap(true, Ordering::SeqCst);
2241 if already_in_use {
2242 return Err(CommandBufferExecError::ExclusiveAlreadyInUse);
2243 }
2244 }
2245 SubmitState::Concurrent => (),
2246 };
2247
2248 let err = match self.inner.lock_submit(future, queue) {
2249 Ok(()) => return Ok(()),
2250 Err(err) => err,
2251 };
2252
2253 // If `self.inner.lock_submit()` failed, we revert action.
2254 match self.submit_state {
2255 SubmitState::OneTime {
2256 ref already_submitted,
2257 } => {
2258 already_submitted.store(false, Ordering::SeqCst);
2259 }
2260 SubmitState::ExclusiveUse { ref in_use } => {
2261 in_use.store(false, Ordering::SeqCst);
2262 }
2263 SubmitState::Concurrent => (),
2264 };
2265
2266 Err(err)
2267 }
2268
2269 #[inline]
unlock(&self)2270 unsafe fn unlock(&self) {
2271 // Because of panic safety, we unlock the inner command buffer first.
2272 self.inner.unlock();
2273
2274 match self.submit_state {
2275 SubmitState::OneTime {
2276 ref already_submitted,
2277 } => {
2278 debug_assert!(already_submitted.load(Ordering::SeqCst));
2279 }
2280 SubmitState::ExclusiveUse { ref in_use } => {
2281 let old_val = in_use.swap(false, Ordering::SeqCst);
2282 debug_assert!(old_val);
2283 }
2284 SubmitState::Concurrent => (),
2285 };
2286 }
2287
2288 #[inline]
check_buffer_access( &self, buffer: &dyn BufferAccess, exclusive: bool, queue: &Queue, ) -> Result<Option<(PipelineStages, AccessFlags)>, AccessCheckError>2289 fn check_buffer_access(
2290 &self,
2291 buffer: &dyn BufferAccess,
2292 exclusive: bool,
2293 queue: &Queue,
2294 ) -> Result<Option<(PipelineStages, AccessFlags)>, AccessCheckError> {
2295 self.inner.check_buffer_access(buffer, exclusive, queue)
2296 }
2297
2298 #[inline]
check_image_access( &self, image: &dyn ImageAccess, layout: ImageLayout, exclusive: bool, queue: &Queue, ) -> Result<Option<(PipelineStages, AccessFlags)>, AccessCheckError>2299 fn check_image_access(
2300 &self,
2301 image: &dyn ImageAccess,
2302 layout: ImageLayout,
2303 exclusive: bool,
2304 queue: &Queue,
2305 ) -> Result<Option<(PipelineStages, AccessFlags)>, AccessCheckError> {
2306 self.inner
2307 .check_image_access(image, layout, exclusive, queue)
2308 }
2309 }
2310
2311 pub struct SecondaryAutoCommandBuffer<P = StandardCommandPoolAlloc> {
2312 inner: SyncCommandBuffer,
2313 pool_alloc: P, // Safety: must be dropped after `inner`
2314 inheritance: CommandBufferInheritance<Box<dyn FramebufferAbstract + Send + Sync>>,
2315
2316 // Tracks usage of the command buffer on the GPU.
2317 submit_state: SubmitState,
2318 }
2319
2320 unsafe impl<P> DeviceOwned for SecondaryAutoCommandBuffer<P> {
2321 #[inline]
device(&self) -> &Arc<Device>2322 fn device(&self) -> &Arc<Device> {
2323 self.inner.device()
2324 }
2325 }
2326
2327 unsafe impl<P> SecondaryCommandBuffer for SecondaryAutoCommandBuffer<P> {
2328 #[inline]
inner(&self) -> &UnsafeCommandBuffer2329 fn inner(&self) -> &UnsafeCommandBuffer {
2330 self.inner.as_ref()
2331 }
2332
2333 #[inline]
lock_record(&self) -> Result<(), CommandBufferExecError>2334 fn lock_record(&self) -> Result<(), CommandBufferExecError> {
2335 match self.submit_state {
2336 SubmitState::OneTime {
2337 ref already_submitted,
2338 } => {
2339 let was_already_submitted = already_submitted.swap(true, Ordering::SeqCst);
2340 if was_already_submitted {
2341 return Err(CommandBufferExecError::OneTimeSubmitAlreadySubmitted);
2342 }
2343 }
2344 SubmitState::ExclusiveUse { ref in_use } => {
2345 let already_in_use = in_use.swap(true, Ordering::SeqCst);
2346 if already_in_use {
2347 return Err(CommandBufferExecError::ExclusiveAlreadyInUse);
2348 }
2349 }
2350 SubmitState::Concurrent => (),
2351 };
2352
2353 Ok(())
2354 }
2355
2356 #[inline]
unlock(&self)2357 unsafe fn unlock(&self) {
2358 match self.submit_state {
2359 SubmitState::OneTime {
2360 ref already_submitted,
2361 } => {
2362 debug_assert!(already_submitted.load(Ordering::SeqCst));
2363 }
2364 SubmitState::ExclusiveUse { ref in_use } => {
2365 let old_val = in_use.swap(false, Ordering::SeqCst);
2366 debug_assert!(old_val);
2367 }
2368 SubmitState::Concurrent => (),
2369 };
2370 }
2371
inheritance(&self) -> CommandBufferInheritance<&dyn FramebufferAbstract>2372 fn inheritance(&self) -> CommandBufferInheritance<&dyn FramebufferAbstract> {
2373 CommandBufferInheritance {
2374 render_pass: self.inheritance.render_pass.as_ref().map(
2375 |CommandBufferInheritanceRenderPass {
2376 subpass,
2377 framebuffer,
2378 }| {
2379 CommandBufferInheritanceRenderPass {
2380 subpass: subpass.clone(),
2381 framebuffer: framebuffer.as_ref().map(|f| f.as_ref() as &_),
2382 }
2383 },
2384 ),
2385 occlusion_query: self.inheritance.occlusion_query,
2386 query_statistics_flags: self.inheritance.query_statistics_flags,
2387 }
2388 }
2389
2390 #[inline]
num_buffers(&self) -> usize2391 fn num_buffers(&self) -> usize {
2392 self.inner.num_buffers()
2393 }
2394
2395 #[inline]
buffer(&self, index: usize) -> Option<(&dyn BufferAccess, PipelineMemoryAccess)>2396 fn buffer(&self, index: usize) -> Option<(&dyn BufferAccess, PipelineMemoryAccess)> {
2397 self.inner.buffer(index)
2398 }
2399
2400 #[inline]
num_images(&self) -> usize2401 fn num_images(&self) -> usize {
2402 self.inner.num_images()
2403 }
2404
2405 #[inline]
image( &self, index: usize, ) -> Option<( &dyn ImageAccess, PipelineMemoryAccess, ImageLayout, ImageLayout, ImageUninitializedSafe, )>2406 fn image(
2407 &self,
2408 index: usize,
2409 ) -> Option<(
2410 &dyn ImageAccess,
2411 PipelineMemoryAccess,
2412 ImageLayout,
2413 ImageLayout,
2414 ImageUninitializedSafe,
2415 )> {
2416 self.inner.image(index)
2417 }
2418 }
2419
2420 // Whether the command buffer can be submitted.
2421 #[derive(Debug)]
2422 enum SubmitState {
2423 // The command buffer was created with the "SimultaneousUse" flag. Can always be submitted at
2424 // any time.
2425 Concurrent,
2426
2427 // The command buffer can only be submitted once simultaneously.
2428 ExclusiveUse {
2429 // True if the command buffer is current in use by the GPU.
2430 in_use: AtomicBool,
2431 },
2432
2433 // The command buffer can only ever be submitted once.
2434 OneTime {
2435 // True if the command buffer has already been submitted once and can be no longer be
2436 // submitted.
2437 already_submitted: AtomicBool,
2438 },
2439 }
2440
2441 macro_rules! err_gen {
2442 ($name:ident { $($err:ident,)+ }) => (
2443 #[derive(Debug, Clone)]
2444 pub enum $name {
2445 $(
2446 $err($err),
2447 )+
2448 }
2449
2450 impl error::Error for $name {
2451 #[inline]
2452 fn source(&self) -> Option<&(dyn error::Error + 'static)> {
2453 match *self {
2454 $(
2455 $name::$err(ref err) => Some(err),
2456 )+
2457 }
2458 }
2459 }
2460
2461 impl fmt::Display for $name {
2462 #[inline]
2463 fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
2464 write!(fmt, "{}", match *self {
2465 $(
2466 $name::$err(_) => {
2467 concat!("a ", stringify!($err))
2468 }
2469 )+
2470 })
2471 }
2472 }
2473
2474 $(
2475 impl From<$err> for $name {
2476 #[inline]
2477 fn from(err: $err) -> $name {
2478 $name::$err(err)
2479 }
2480 }
2481 )+
2482 );
2483 }
2484
2485 err_gen!(BuildError {
2486 AutoCommandBufferBuilderContextError,
2487 OomError,
2488 });
2489
2490 err_gen!(BeginRenderPassError {
2491 AutoCommandBufferBuilderContextError,
2492 SyncCommandBufferBuilderError,
2493 });
2494
2495 err_gen!(CopyImageError {
2496 AutoCommandBufferBuilderContextError,
2497 CheckCopyImageError,
2498 SyncCommandBufferBuilderError,
2499 });
2500
2501 err_gen!(BlitImageError {
2502 AutoCommandBufferBuilderContextError,
2503 CheckBlitImageError,
2504 SyncCommandBufferBuilderError,
2505 });
2506
2507 err_gen!(ClearColorImageError {
2508 AutoCommandBufferBuilderContextError,
2509 CheckClearColorImageError,
2510 SyncCommandBufferBuilderError,
2511 });
2512
2513 err_gen!(CopyBufferError {
2514 AutoCommandBufferBuilderContextError,
2515 CheckCopyBufferError,
2516 SyncCommandBufferBuilderError,
2517 });
2518
2519 err_gen!(CopyBufferImageError {
2520 AutoCommandBufferBuilderContextError,
2521 CheckCopyBufferImageError,
2522 SyncCommandBufferBuilderError,
2523 });
2524
2525 err_gen!(CopyQueryPoolResultsError {
2526 AutoCommandBufferBuilderContextError,
2527 CheckCopyQueryPoolResultsError,
2528 SyncCommandBufferBuilderError,
2529 });
2530
2531 err_gen!(FillBufferError {
2532 AutoCommandBufferBuilderContextError,
2533 CheckFillBufferError,
2534 });
2535
2536 err_gen!(DebugMarkerError {
2537 AutoCommandBufferBuilderContextError,
2538 CheckColorError,
2539 });
2540
2541 err_gen!(DispatchError {
2542 AutoCommandBufferBuilderContextError,
2543 CheckPushConstantsValidityError,
2544 CheckDescriptorSetsValidityError,
2545 CheckDispatchError,
2546 SyncCommandBufferBuilderError,
2547 });
2548
2549 err_gen!(DispatchIndirectError {
2550 AutoCommandBufferBuilderContextError,
2551 CheckPushConstantsValidityError,
2552 CheckDescriptorSetsValidityError,
2553 CheckIndirectBufferError,
2554 SyncCommandBufferBuilderError,
2555 });
2556
2557 err_gen!(DrawError {
2558 AutoCommandBufferBuilderContextError,
2559 CheckDynamicStateValidityError,
2560 CheckPushConstantsValidityError,
2561 CheckDescriptorSetsValidityError,
2562 CheckVertexBufferError,
2563 SyncCommandBufferBuilderError,
2564 });
2565
2566 err_gen!(DrawIndexedError {
2567 AutoCommandBufferBuilderContextError,
2568 CheckDynamicStateValidityError,
2569 CheckPushConstantsValidityError,
2570 CheckDescriptorSetsValidityError,
2571 CheckVertexBufferError,
2572 CheckIndexBufferError,
2573 SyncCommandBufferBuilderError,
2574 });
2575
2576 err_gen!(DrawIndirectError {
2577 AutoCommandBufferBuilderContextError,
2578 CheckDynamicStateValidityError,
2579 CheckPushConstantsValidityError,
2580 CheckDescriptorSetsValidityError,
2581 CheckVertexBufferError,
2582 CheckIndirectBufferError,
2583 SyncCommandBufferBuilderError,
2584 });
2585
2586 err_gen!(DrawIndexedIndirectError {
2587 AutoCommandBufferBuilderContextError,
2588 CheckDynamicStateValidityError,
2589 CheckPushConstantsValidityError,
2590 CheckDescriptorSetsValidityError,
2591 CheckVertexBufferError,
2592 CheckIndexBufferError,
2593 CheckIndirectBufferError,
2594 SyncCommandBufferBuilderError,
2595 });
2596
2597 err_gen!(ExecuteCommandsError {
2598 AutoCommandBufferBuilderContextError,
2599 SyncCommandBufferBuilderError,
2600 });
2601
2602 err_gen!(BeginQueryError {
2603 AutoCommandBufferBuilderContextError,
2604 CheckBeginQueryError,
2605 });
2606
2607 err_gen!(EndQueryError {
2608 AutoCommandBufferBuilderContextError,
2609 CheckEndQueryError,
2610 });
2611
2612 err_gen!(WriteTimestampError {
2613 AutoCommandBufferBuilderContextError,
2614 CheckWriteTimestampError,
2615 });
2616
2617 err_gen!(ResetQueryPoolError {
2618 AutoCommandBufferBuilderContextError,
2619 CheckResetQueryPoolError,
2620 });
2621
2622 err_gen!(UpdateBufferError {
2623 AutoCommandBufferBuilderContextError,
2624 CheckUpdateBufferError,
2625 });
2626
2627 #[derive(Debug, Copy, Clone)]
2628 pub enum AutoCommandBufferBuilderContextError {
2629 /// Operation forbidden inside of a render pass.
2630 ForbiddenInsideRenderPass,
2631 /// Operation forbidden outside of a render pass.
2632 ForbiddenOutsideRenderPass,
2633 /// Tried to use a secondary command buffer with a specified framebuffer that is
2634 /// incompatible with the current framebuffer.
2635 IncompatibleFramebuffer,
2636 /// Tried to use a graphics pipeline or secondary command buffer whose render pass
2637 /// is incompatible with the current render pass.
2638 IncompatibleRenderPass,
2639 /// The queue family doesn't allow this operation.
2640 NotSupportedByQueueFamily,
2641 /// Tried to end a render pass with subpasses remaining, or tried to go to next subpass with no
2642 /// subpass remaining.
2643 NumSubpassesMismatch {
2644 /// Actual number of subpasses in the current render pass.
2645 actual: u32,
2646 /// Current subpass index before the failing command.
2647 current: u32,
2648 },
2649 /// A query is active that conflicts with the current operation.
2650 QueryIsActive,
2651 /// This query was not active.
2652 QueryNotActive,
2653 /// A query is active that is not included in the `inheritance` of the secondary command buffer.
2654 QueryNotInherited,
2655 /// Tried to use a graphics pipeline or secondary command buffer whose subpass index
2656 /// didn't match the current subpass index.
2657 WrongSubpassIndex,
2658 /// Tried to execute a secondary command buffer inside a subpass that only allows inline
2659 /// commands, or a draw command in a subpass that only allows secondary command buffers.
2660 WrongSubpassType,
2661 }
2662
2663 impl error::Error for AutoCommandBufferBuilderContextError {}
2664
2665 impl fmt::Display for AutoCommandBufferBuilderContextError {
2666 #[inline]
fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error>2667 fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
2668 write!(
2669 fmt,
2670 "{}",
2671 match *self {
2672 AutoCommandBufferBuilderContextError::ForbiddenInsideRenderPass => {
2673 "operation forbidden inside of a render pass"
2674 }
2675 AutoCommandBufferBuilderContextError::ForbiddenOutsideRenderPass => {
2676 "operation forbidden outside of a render pass"
2677 }
2678 AutoCommandBufferBuilderContextError::IncompatibleFramebuffer => {
2679 "tried to use a secondary command buffer with a specified framebuffer that is \
2680 incompatible with the current framebuffer"
2681 }
2682 AutoCommandBufferBuilderContextError::IncompatibleRenderPass => {
2683 "tried to use a graphics pipeline or secondary command buffer whose render pass \
2684 is incompatible with the current render pass"
2685 }
2686 AutoCommandBufferBuilderContextError::NotSupportedByQueueFamily => {
2687 "the queue family doesn't allow this operation"
2688 }
2689 AutoCommandBufferBuilderContextError::NumSubpassesMismatch { .. } => {
2690 "tried to end a render pass with subpasses remaining, or tried to go to next \
2691 subpass with no subpass remaining"
2692 }
2693 AutoCommandBufferBuilderContextError::QueryIsActive => {
2694 "a query is active that conflicts with the current operation"
2695 }
2696 AutoCommandBufferBuilderContextError::QueryNotActive => {
2697 "this query was not active"
2698 }
2699 AutoCommandBufferBuilderContextError::QueryNotInherited => {
2700 "a query is active that is not included in the inheritance of the secondary command buffer"
2701 }
2702 AutoCommandBufferBuilderContextError::WrongSubpassIndex => {
2703 "tried to use a graphics pipeline whose subpass index didn't match the current \
2704 subpass index"
2705 }
2706 AutoCommandBufferBuilderContextError::WrongSubpassType => {
2707 "tried to execute a secondary command buffer inside a subpass that only allows \
2708 inline commands, or a draw command in a subpass that only allows secondary \
2709 command buffers"
2710 }
2711 }
2712 )
2713 }
2714 }
2715
2716 #[cfg(test)]
2717 mod tests {
2718 use crate::buffer::BufferUsage;
2719 use crate::buffer::CpuAccessibleBuffer;
2720 use crate::command_buffer::synced::SyncCommandBufferBuilderError;
2721 use crate::command_buffer::AutoCommandBufferBuilder;
2722 use crate::command_buffer::CommandBufferExecError;
2723 use crate::command_buffer::CommandBufferUsage;
2724 use crate::command_buffer::ExecuteCommandsError;
2725 use crate::command_buffer::PrimaryCommandBuffer;
2726 use crate::device::physical::PhysicalDevice;
2727 use crate::device::Device;
2728 use crate::device::DeviceExtensions;
2729 use crate::device::Features;
2730 use crate::sync::GpuFuture;
2731 use std::sync::Arc;
2732
2733 #[test]
copy_buffer_dimensions()2734 fn copy_buffer_dimensions() {
2735 let instance = instance!();
2736
2737 let phys = match PhysicalDevice::enumerate(&instance).next() {
2738 Some(p) => p,
2739 None => return,
2740 };
2741
2742 let queue_family = match phys.queue_families().next() {
2743 Some(q) => q,
2744 None => return,
2745 };
2746
2747 let (device, mut queues) = Device::new(
2748 phys,
2749 &Features::none(),
2750 &DeviceExtensions::none(),
2751 std::iter::once((queue_family, 0.5)),
2752 )
2753 .unwrap();
2754
2755 let queue = queues.next().unwrap();
2756
2757 let source = CpuAccessibleBuffer::from_iter(
2758 device.clone(),
2759 BufferUsage::all(),
2760 true,
2761 [1_u32, 2].iter().copied(),
2762 )
2763 .unwrap();
2764
2765 let destination = CpuAccessibleBuffer::from_iter(
2766 device.clone(),
2767 BufferUsage::all(),
2768 true,
2769 [0_u32, 10, 20, 3, 4].iter().copied(),
2770 )
2771 .unwrap();
2772
2773 let mut cbb = AutoCommandBufferBuilder::primary(
2774 device.clone(),
2775 queue.family(),
2776 CommandBufferUsage::OneTimeSubmit,
2777 )
2778 .unwrap();
2779
2780 cbb.copy_buffer_dimensions(source.clone(), 0, destination.clone(), 1, 2)
2781 .unwrap();
2782
2783 let cb = cbb.build().unwrap();
2784
2785 let future = cb
2786 .execute(queue.clone())
2787 .unwrap()
2788 .then_signal_fence_and_flush()
2789 .unwrap();
2790 future.wait(None).unwrap();
2791
2792 let result = destination.read().unwrap();
2793
2794 assert_eq!(*result, [0_u32, 1, 2, 3, 4]);
2795 }
2796
2797 #[test]
secondary_nonconcurrent_conflict()2798 fn secondary_nonconcurrent_conflict() {
2799 let (device, queue) = gfx_dev_and_queue!();
2800
2801 // Make a secondary CB that doesn't support simultaneous use.
2802 let builder = AutoCommandBufferBuilder::secondary_compute(
2803 device.clone(),
2804 queue.family(),
2805 CommandBufferUsage::MultipleSubmit,
2806 )
2807 .unwrap();
2808 let secondary = Arc::new(builder.build().unwrap());
2809
2810 {
2811 let mut builder = AutoCommandBufferBuilder::primary(
2812 device.clone(),
2813 queue.family(),
2814 CommandBufferUsage::SimultaneousUse,
2815 )
2816 .unwrap();
2817
2818 // Add the secondary a first time
2819 builder.execute_commands(secondary.clone()).unwrap();
2820
2821 // Recording the same non-concurrent secondary command buffer twice into the same
2822 // primary is an error.
2823 assert!(matches!(
2824 builder.execute_commands(secondary.clone()),
2825 Err(ExecuteCommandsError::SyncCommandBufferBuilderError(
2826 SyncCommandBufferBuilderError::ExecError(
2827 CommandBufferExecError::ExclusiveAlreadyInUse
2828 )
2829 ))
2830 ));
2831 }
2832
2833 {
2834 let mut builder = AutoCommandBufferBuilder::primary(
2835 device.clone(),
2836 queue.family(),
2837 CommandBufferUsage::SimultaneousUse,
2838 )
2839 .unwrap();
2840 builder.execute_commands(secondary.clone()).unwrap();
2841 let cb1 = builder.build().unwrap();
2842
2843 let mut builder = AutoCommandBufferBuilder::primary(
2844 device.clone(),
2845 queue.family(),
2846 CommandBufferUsage::SimultaneousUse,
2847 )
2848 .unwrap();
2849
2850 // Recording the same non-concurrent secondary command buffer into multiple
2851 // primaries is an error.
2852 assert!(matches!(
2853 builder.execute_commands(secondary.clone()),
2854 Err(ExecuteCommandsError::SyncCommandBufferBuilderError(
2855 SyncCommandBufferBuilderError::ExecError(
2856 CommandBufferExecError::ExclusiveAlreadyInUse
2857 )
2858 ))
2859 ));
2860
2861 std::mem::drop(cb1);
2862
2863 // Now that the first cb is dropped, we should be able to record.
2864 builder.execute_commands(secondary.clone()).unwrap();
2865 }
2866 }
2867 }
2868