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 super::{ 11 CommandBufferInheritanceInfo, CommandBufferResourcesUsage, CommandBufferState, 12 CommandBufferUsage, SecondaryCommandBufferResourcesUsage, SemaphoreSubmitInfo, SubmitInfo, 13 }; 14 use crate::{ 15 buffer::Buffer, 16 device::{Device, DeviceOwned, Queue}, 17 image::{sys::Image, ImageLayout}, 18 swapchain::Swapchain, 19 sync::{ 20 future::{ 21 now, AccessCheckError, AccessError, FlushError, GpuFuture, NowFuture, SubmitAnyBuilder, 22 }, 23 PipelineStages, 24 }, 25 DeviceSize, SafeDeref, VulkanObject, 26 }; 27 use parking_lot::{Mutex, MutexGuard}; 28 use std::{ 29 borrow::Cow, 30 error::Error, 31 fmt::{Debug, Display, Error as FmtError, Formatter}, 32 ops::Range, 33 sync::{ 34 atomic::{AtomicBool, Ordering}, 35 Arc, 36 }, 37 thread, 38 }; 39 40 pub unsafe trait PrimaryCommandBufferAbstract: 41 VulkanObject<Handle = ash::vk::CommandBuffer> + DeviceOwned + Send + Sync 42 { 43 /// Returns the usage of this command buffer. usage(&self) -> CommandBufferUsage44 fn usage(&self) -> CommandBufferUsage; 45 46 /// Executes this command buffer on a queue. 47 /// 48 /// This function returns an object that implements the [`GpuFuture`] trait. See the 49 /// documentation of the [`future`][crate::sync::future] module for more information. 50 /// 51 /// The command buffer is not actually executed until you call [`flush()`][GpuFuture::flush] on 52 /// the future. You are encouraged to chain together as many futures as possible prior to 53 /// calling [`flush()`][GpuFuture::flush]. In order to know when the future has completed, call 54 /// one of [`then_signal_fence()`][GpuFuture::then_signal_fence] or 55 /// [`then_signal_semaphore()`][GpuFuture::then_signal_semaphore]. You can do both together 56 /// with [`then_signal_fence_and_flush()`][GpuFuture::then_signal_fence_and_flush] or 57 /// [`then_signal_semaphore_and_flush()`][GpuFuture::then_signal_semaphore_and_flush], 58 /// respectively. 59 /// 60 /// > **Note**: In the future this function may return `-> impl GpuFuture` instead of a 61 /// > concrete type. 62 /// 63 /// > **Note**: This is just a shortcut for `execute_after(vulkano::sync::now(), queue)`. 64 /// 65 /// # Panics 66 /// 67 /// - Panics if the device of the command buffer is not the same as the device of the future. 68 #[inline] execute( self, queue: Arc<Queue>, ) -> Result<CommandBufferExecFuture<NowFuture>, CommandBufferExecError> where Self: Sized + 'static,69 fn execute( 70 self, 71 queue: Arc<Queue>, 72 ) -> Result<CommandBufferExecFuture<NowFuture>, CommandBufferExecError> 73 where 74 Self: Sized + 'static, 75 { 76 let device = queue.device().clone(); 77 self.execute_after(now(device), queue) 78 } 79 80 /// Executes the command buffer after an existing future. 81 /// 82 /// This function returns an object that implements the [`GpuFuture`] trait. See the 83 /// documentation of the [`future`][crate::sync::future] module for more information. 84 /// 85 /// The command buffer is not actually executed until you call [`flush()`][GpuFuture::flush] on 86 /// the future. You are encouraged to chain together as many futures as possible prior to 87 /// calling [`flush()`][GpuFuture::flush]. In order to know when the future has completed, call 88 /// one of [`then_signal_fence()`][GpuFuture::then_signal_fence] or 89 /// [`then_signal_semaphore()`][GpuFuture::then_signal_semaphore]. You can do both together 90 /// with [`then_signal_fence_and_flush()`][GpuFuture::then_signal_fence_and_flush] or 91 /// [`then_signal_semaphore_and_flush()`][GpuFuture::then_signal_semaphore_and_flush], 92 /// respectively. 93 /// 94 /// > **Note**: In the future this function may return `-> impl GpuFuture` instead of a 95 /// > concrete type. 96 /// 97 /// This function requires the `'static` lifetime to be on the command buffer. This is because 98 /// this function returns a `CommandBufferExecFuture` whose job is to lock resources and keep 99 /// them alive while they are in use by the GPU. If `'static` wasn't required, you could call 100 /// `std::mem::forget` on that object and "unlock" these resources. For more information about 101 /// this problem, search the web for "rust thread scoped leakpocalypse". 102 /// 103 /// # Panics 104 /// 105 /// - Panics if the device of the command buffer is not the same as the device of the future. execute_after<F>( self, future: F, queue: Arc<Queue>, ) -> Result<CommandBufferExecFuture<F>, CommandBufferExecError> where Self: Sized + 'static, F: GpuFuture,106 fn execute_after<F>( 107 self, 108 future: F, 109 queue: Arc<Queue>, 110 ) -> Result<CommandBufferExecFuture<F>, CommandBufferExecError> 111 where 112 Self: Sized + 'static, 113 F: GpuFuture, 114 { 115 assert_eq!(self.device().handle(), future.device().handle()); 116 117 if !future.queue_change_allowed() { 118 assert!(future.queue().unwrap() == queue); 119 } 120 121 Ok(CommandBufferExecFuture { 122 previous: future, 123 command_buffer: Arc::new(self), 124 queue, 125 submitted: Mutex::new(false), 126 finished: AtomicBool::new(false), 127 }) 128 } 129 130 #[doc(hidden)] state(&self) -> MutexGuard<'_, CommandBufferState>131 fn state(&self) -> MutexGuard<'_, CommandBufferState>; 132 133 #[doc(hidden)] resources_usage(&self) -> &CommandBufferResourcesUsage134 fn resources_usage(&self) -> &CommandBufferResourcesUsage; 135 } 136 137 impl Debug for dyn PrimaryCommandBufferAbstract { fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError>138 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { 139 Debug::fmt(&self.handle(), f) 140 } 141 } 142 143 unsafe impl<T> PrimaryCommandBufferAbstract for T 144 where 145 T: VulkanObject<Handle = ash::vk::CommandBuffer> + SafeDeref + Send + Sync, 146 T::Target: PrimaryCommandBufferAbstract, 147 { usage(&self) -> CommandBufferUsage148 fn usage(&self) -> CommandBufferUsage { 149 (**self).usage() 150 } 151 state(&self) -> MutexGuard<'_, CommandBufferState>152 fn state(&self) -> MutexGuard<'_, CommandBufferState> { 153 (**self).state() 154 } 155 resources_usage(&self) -> &CommandBufferResourcesUsage156 fn resources_usage(&self) -> &CommandBufferResourcesUsage { 157 (**self).resources_usage() 158 } 159 } 160 161 pub unsafe trait SecondaryCommandBufferAbstract: 162 VulkanObject<Handle = ash::vk::CommandBuffer> + DeviceOwned + Send + Sync 163 { 164 /// Returns the usage of this command buffer. usage(&self) -> CommandBufferUsage165 fn usage(&self) -> CommandBufferUsage; 166 167 /// Returns a `CommandBufferInheritance` value describing the properties that the command 168 /// buffer inherits from its parent primary command buffer. inheritance_info(&self) -> &CommandBufferInheritanceInfo169 fn inheritance_info(&self) -> &CommandBufferInheritanceInfo; 170 171 /// Checks whether this command buffer is allowed to be recorded to a command buffer, 172 /// and if so locks it. 173 /// 174 /// If you call this function, then you should call `unlock` afterwards. lock_record(&self) -> Result<(), CommandBufferExecError>175 fn lock_record(&self) -> Result<(), CommandBufferExecError>; 176 177 /// Unlocks the command buffer. Should be called once for each call to `lock_record`. 178 /// 179 /// # Safety 180 /// 181 /// Must not be called if you haven't called `lock_record` before. unlock(&self)182 unsafe fn unlock(&self); 183 184 #[doc(hidden)] resources_usage(&self) -> &SecondaryCommandBufferResourcesUsage185 fn resources_usage(&self) -> &SecondaryCommandBufferResourcesUsage; 186 } 187 188 unsafe impl<T> SecondaryCommandBufferAbstract for T 189 where 190 T: VulkanObject<Handle = ash::vk::CommandBuffer> + SafeDeref + Send + Sync, 191 T::Target: SecondaryCommandBufferAbstract, 192 { usage(&self) -> CommandBufferUsage193 fn usage(&self) -> CommandBufferUsage { 194 (**self).usage() 195 } 196 inheritance_info(&self) -> &CommandBufferInheritanceInfo197 fn inheritance_info(&self) -> &CommandBufferInheritanceInfo { 198 (**self).inheritance_info() 199 } 200 lock_record(&self) -> Result<(), CommandBufferExecError>201 fn lock_record(&self) -> Result<(), CommandBufferExecError> { 202 (**self).lock_record() 203 } 204 unlock(&self)205 unsafe fn unlock(&self) { 206 (**self).unlock(); 207 } 208 resources_usage(&self) -> &SecondaryCommandBufferResourcesUsage209 fn resources_usage(&self) -> &SecondaryCommandBufferResourcesUsage { 210 (**self).resources_usage() 211 } 212 } 213 214 /// Represents a command buffer being executed by the GPU and the moment when the execution 215 /// finishes. 216 #[derive(Debug)] 217 #[must_use = "Dropping this object will immediately block the thread until the GPU has finished processing the submission"] 218 pub struct CommandBufferExecFuture<F> 219 where 220 F: GpuFuture, 221 { 222 previous: F, 223 command_buffer: Arc<dyn PrimaryCommandBufferAbstract>, 224 queue: Arc<Queue>, 225 // True if the command buffer has already been submitted. 226 // If flush is called multiple times, we want to block so that only one flushing is executed. 227 // Therefore we use a `Mutex<bool>` and not an `AtomicBool`. 228 submitted: Mutex<bool>, 229 finished: AtomicBool, 230 } 231 232 impl<F> CommandBufferExecFuture<F> 233 where 234 F: GpuFuture, 235 { 236 // Implementation of `build_submission`. Doesn't check whenever the future was already flushed. 237 // You must make sure to not submit same command buffer multiple times. build_submission_impl(&self) -> Result<SubmitAnyBuilder, FlushError>238 unsafe fn build_submission_impl(&self) -> Result<SubmitAnyBuilder, FlushError> { 239 Ok(match self.previous.build_submission()? { 240 SubmitAnyBuilder::Empty => SubmitAnyBuilder::CommandBuffer( 241 SubmitInfo { 242 command_buffers: vec![self.command_buffer.clone()], 243 ..Default::default() 244 }, 245 None, 246 ), 247 SubmitAnyBuilder::SemaphoresWait(semaphores) => { 248 SubmitAnyBuilder::CommandBuffer( 249 SubmitInfo { 250 wait_semaphores: semaphores 251 .into_iter() 252 .map(|semaphore| { 253 SemaphoreSubmitInfo { 254 // TODO: correct stages ; hard 255 stages: PipelineStages::ALL_COMMANDS, 256 ..SemaphoreSubmitInfo::semaphore(semaphore) 257 } 258 }) 259 .collect(), 260 command_buffers: vec![self.command_buffer.clone()], 261 ..Default::default() 262 }, 263 None, 264 ) 265 } 266 SubmitAnyBuilder::CommandBuffer(mut submit_info, fence) => { 267 // FIXME: add pipeline barrier 268 submit_info 269 .command_buffers 270 .push(self.command_buffer.clone()); 271 SubmitAnyBuilder::CommandBuffer(submit_info, fence) 272 } 273 SubmitAnyBuilder::QueuePresent(_) | SubmitAnyBuilder::BindSparse(_, _) => { 274 unimplemented!() // TODO: 275 /*present.submit(); // TODO: wrong 276 let mut builder = SubmitCommandBufferBuilder::new(); 277 builder.add_command_buffer(self.command_buffer.inner()); 278 SubmitAnyBuilder::CommandBuffer(builder)*/ 279 } 280 }) 281 } 282 } 283 284 unsafe impl<F> GpuFuture for CommandBufferExecFuture<F> 285 where 286 F: GpuFuture, 287 { cleanup_finished(&mut self)288 fn cleanup_finished(&mut self) { 289 self.previous.cleanup_finished(); 290 } 291 build_submission(&self) -> Result<SubmitAnyBuilder, FlushError>292 unsafe fn build_submission(&self) -> Result<SubmitAnyBuilder, FlushError> { 293 if *self.submitted.lock() { 294 return Ok(SubmitAnyBuilder::Empty); 295 } 296 297 self.build_submission_impl() 298 } 299 flush(&self) -> Result<(), FlushError>300 fn flush(&self) -> Result<(), FlushError> { 301 unsafe { 302 let mut submitted = self.submitted.lock(); 303 if *submitted { 304 return Ok(()); 305 } 306 307 match self.build_submission_impl()? { 308 SubmitAnyBuilder::Empty => {} 309 SubmitAnyBuilder::CommandBuffer(submit_info, fence) => { 310 self.queue.with(|mut q| { 311 q.submit_with_future(submit_info, fence, &self.previous, &self.queue) 312 })?; 313 } 314 _ => unreachable!(), 315 }; 316 317 // Only write `true` here in order to try again next time if we failed to submit. 318 *submitted = true; 319 Ok(()) 320 } 321 } 322 signal_finished(&self)323 unsafe fn signal_finished(&self) { 324 self.finished.store(true, Ordering::SeqCst); 325 self.previous.signal_finished(); 326 } 327 queue_change_allowed(&self) -> bool328 fn queue_change_allowed(&self) -> bool { 329 false 330 } 331 queue(&self) -> Option<Arc<Queue>>332 fn queue(&self) -> Option<Arc<Queue>> { 333 Some(self.queue.clone()) 334 } 335 check_buffer_access( &self, buffer: &Buffer, range: Range<DeviceSize>, exclusive: bool, queue: &Queue, ) -> Result<(), AccessCheckError>336 fn check_buffer_access( 337 &self, 338 buffer: &Buffer, 339 range: Range<DeviceSize>, 340 exclusive: bool, 341 queue: &Queue, 342 ) -> Result<(), AccessCheckError> { 343 let resources_usage = self.command_buffer.resources_usage(); 344 let usage = match resources_usage.buffer_indices.get(buffer) { 345 Some(&index) => &resources_usage.buffers[index], 346 None => return Err(AccessCheckError::Unknown), 347 }; 348 349 // TODO: check the queue family 350 351 let result = usage 352 .ranges 353 .range(&range) 354 .try_fold((), |_, (_range, range_usage)| { 355 if !range_usage.mutable && exclusive { 356 Err(AccessCheckError::Unknown) 357 } else { 358 Ok(()) 359 } 360 }); 361 362 match result { 363 Ok(()) => Ok(()), 364 Err(AccessCheckError::Denied(err)) => Err(AccessCheckError::Denied(err)), 365 Err(AccessCheckError::Unknown) => self 366 .previous 367 .check_buffer_access(buffer, range, exclusive, queue), 368 } 369 } 370 check_image_access( &self, image: &Image, range: Range<DeviceSize>, exclusive: bool, expected_layout: ImageLayout, queue: &Queue, ) -> Result<(), AccessCheckError>371 fn check_image_access( 372 &self, 373 image: &Image, 374 range: Range<DeviceSize>, 375 exclusive: bool, 376 expected_layout: ImageLayout, 377 queue: &Queue, 378 ) -> Result<(), AccessCheckError> { 379 let resources_usage = self.command_buffer.resources_usage(); 380 let usage = match resources_usage.image_indices.get(image) { 381 Some(&index) => &resources_usage.images[index], 382 None => return Err(AccessCheckError::Unknown), 383 }; 384 385 // TODO: check the queue family 386 387 let result = usage 388 .ranges 389 .range(&range) 390 .try_fold((), |_, (_range, range_usage)| { 391 if expected_layout != ImageLayout::Undefined 392 && range_usage.final_layout != expected_layout 393 { 394 return Err(AccessCheckError::Denied( 395 AccessError::UnexpectedImageLayout { 396 allowed: range_usage.final_layout, 397 requested: expected_layout, 398 }, 399 )); 400 } 401 402 if !range_usage.mutable && exclusive { 403 Err(AccessCheckError::Unknown) 404 } else { 405 Ok(()) 406 } 407 }); 408 409 match result { 410 Ok(()) => Ok(()), 411 Err(AccessCheckError::Denied(err)) => Err(AccessCheckError::Denied(err)), 412 Err(AccessCheckError::Unknown) => { 413 self.previous 414 .check_image_access(image, range, exclusive, expected_layout, queue) 415 } 416 } 417 } 418 419 #[inline] check_swapchain_image_acquired( &self, swapchain: &Swapchain, image_index: u32, _before: bool, ) -> Result<(), AccessCheckError>420 fn check_swapchain_image_acquired( 421 &self, 422 swapchain: &Swapchain, 423 image_index: u32, 424 _before: bool, 425 ) -> Result<(), AccessCheckError> { 426 self.previous 427 .check_swapchain_image_acquired(swapchain, image_index, false) 428 } 429 } 430 431 unsafe impl<F> DeviceOwned for CommandBufferExecFuture<F> 432 where 433 F: GpuFuture, 434 { device(&self) -> &Arc<Device>435 fn device(&self) -> &Arc<Device> { 436 self.command_buffer.device() 437 } 438 } 439 440 impl<F> Drop for CommandBufferExecFuture<F> 441 where 442 F: GpuFuture, 443 { drop(&mut self)444 fn drop(&mut self) { 445 if !*self.finished.get_mut() && !thread::panicking() { 446 // TODO: handle errors? 447 self.flush().unwrap(); 448 // Block until the queue finished. 449 self.queue.with(|mut q| q.wait_idle()).unwrap(); 450 unsafe { self.previous.signal_finished() }; 451 } 452 } 453 } 454 455 /// Error that can happen when attempting to execute a command buffer. 456 #[derive(Clone, Debug, PartialEq, Eq)] 457 pub enum CommandBufferExecError { 458 /// Access to a resource has been denied. 459 AccessError { 460 error: AccessError, 461 command_name: Cow<'static, str>, 462 command_param: Cow<'static, str>, 463 command_offset: usize, 464 }, 465 466 /// The command buffer or one of the secondary command buffers it executes was created with the 467 /// "one time submit" flag, but has already been submitted it the past. 468 OneTimeSubmitAlreadySubmitted, 469 470 /// The command buffer or one of the secondary command buffers it executes is already in use by 471 /// the GPU and was not created with the "concurrent" flag. 472 ExclusiveAlreadyInUse, 473 // TODO: missing entries (eg. wrong queue family, secondary command buffer) 474 } 475 476 impl Error for CommandBufferExecError { source(&self) -> Option<&(dyn Error + 'static)>477 fn source(&self) -> Option<&(dyn Error + 'static)> { 478 match self { 479 CommandBufferExecError::AccessError { error, .. } => Some(error), 480 _ => None, 481 } 482 } 483 } 484 485 impl Display for CommandBufferExecError { fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError>486 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { 487 write!( 488 f, 489 "{}", 490 match self { 491 CommandBufferExecError::AccessError { .. } => 492 "access to a resource has been denied", 493 CommandBufferExecError::OneTimeSubmitAlreadySubmitted => { 494 "the command buffer or one of the secondary command buffers it executes was \ 495 created with the \"one time submit\" flag, but has already been submitted in \ 496 the past" 497 } 498 CommandBufferExecError::ExclusiveAlreadyInUse => { 499 "the command buffer or one of the secondary command buffers it executes is \ 500 already in use was not created with the \"concurrent\" flag" 501 } 502 } 503 ) 504 } 505 } 506