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