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 pub use self::fence_signal::{FenceSignalFuture, FenceSignalFutureBehavior}; 11 pub use self::join::JoinFuture; 12 pub use self::now::{now, NowFuture}; 13 pub use self::semaphore_signal::SemaphoreSignalFuture; 14 use crate::buffer::BufferAccess; 15 use crate::command_buffer::submit::SubmitAnyBuilder; 16 use crate::command_buffer::submit::SubmitBindSparseError; 17 use crate::command_buffer::submit::SubmitCommandBufferError; 18 use crate::command_buffer::submit::SubmitPresentError; 19 use crate::command_buffer::CommandBufferExecError; 20 use crate::command_buffer::CommandBufferExecFuture; 21 use crate::command_buffer::PrimaryCommandBuffer; 22 use crate::device::DeviceOwned; 23 use crate::device::Queue; 24 use crate::image::ImageAccess; 25 use crate::image::ImageLayout; 26 use crate::swapchain; 27 use crate::swapchain::PresentFuture; 28 use crate::swapchain::PresentRegion; 29 use crate::swapchain::Swapchain; 30 use crate::sync::AccessFlags; 31 use crate::sync::FenceWaitError; 32 use crate::sync::PipelineStages; 33 use crate::OomError; 34 use std::error; 35 use std::fmt; 36 use std::sync::Arc; 37 38 mod fence_signal; 39 mod join; 40 mod now; 41 mod semaphore_signal; 42 43 /// Represents an event that will happen on the GPU in the future. 44 /// 45 /// See the documentation of the `sync` module for explanations about futures. 46 // TODO: consider switching all methods to take `&mut self` for optimization purposes 47 pub unsafe trait GpuFuture: DeviceOwned { 48 /// If possible, checks whether the submission has finished. If so, gives up ownership of the 49 /// resources used by these submissions. 50 /// 51 /// It is highly recommended to call `cleanup_finished` from time to time. Doing so will 52 /// prevent memory usage from increasing over time, and will also destroy the locks on 53 /// resources used by the GPU. cleanup_finished(&mut self)54 fn cleanup_finished(&mut self); 55 56 /// Builds a submission that, if submitted, makes sure that the event represented by this 57 /// `GpuFuture` will happen, and possibly contains extra elements (eg. a semaphore wait or an 58 /// event wait) that makes the dependency with subsequent operations work. 59 /// 60 /// It is the responsibility of the caller to ensure that the submission is going to be 61 /// submitted only once. However keep in mind that this function can perfectly be called 62 /// multiple times (as long as the returned object is only submitted once). 63 /// Also note that calling `flush()` on the future may change the value returned by 64 /// `build_submission()`. 65 /// 66 /// It is however the responsibility of the implementation to not return the same submission 67 /// from multiple different future objects. For example if you implement `GpuFuture` on 68 /// `Arc<Foo>` then `build_submission()` must always return `SubmitAnyBuilder::Empty`, 69 /// otherwise it would be possible for the user to clone the `Arc` and make the same 70 /// submission be submitted multiple times. 71 /// 72 /// It is also the responsibility of the implementation to ensure that it works if you call 73 /// `build_submission()` and submits the returned value without calling `flush()` first. In 74 /// other words, `build_submission()` should perform an implicit flush if necessary. 75 /// 76 /// Once the caller has submitted the submission and has determined that the GPU has finished 77 /// executing it, it should call `signal_finished`. Failure to do so will incur a large runtime 78 /// overhead, as the future will have to block to make sure that it is finished. build_submission(&self) -> Result<SubmitAnyBuilder, FlushError>79 unsafe fn build_submission(&self) -> Result<SubmitAnyBuilder, FlushError>; 80 81 /// Flushes the future and submits to the GPU the actions that will permit this future to 82 /// occur. 83 /// 84 /// The implementation must remember that it was flushed. If the function is called multiple 85 /// times, only the first time must result in a flush. flush(&self) -> Result<(), FlushError>86 fn flush(&self) -> Result<(), FlushError>; 87 88 /// Sets the future to its "complete" state, meaning that it can safely be destroyed. 89 /// 90 /// This must only be done if you called `build_submission()`, submitted the returned 91 /// submission, and determined that it was finished. 92 /// 93 /// The implementation must be aware that this function can be called multiple times on the 94 /// same future. signal_finished(&self)95 unsafe fn signal_finished(&self); 96 97 /// Returns the queue that triggers the event. Returns `None` if unknown or irrelevant. 98 /// 99 /// If this function returns `None` and `queue_change_allowed` returns `false`, then a panic 100 /// is likely to occur if you use this future. This is only a problem if you implement 101 /// the `GpuFuture` trait yourself for a type outside of vulkano. queue(&self) -> Option<Arc<Queue>>102 fn queue(&self) -> Option<Arc<Queue>>; 103 104 /// Returns `true` if elements submitted after this future can be submitted to a different 105 /// queue than the other returned by `queue()`. queue_change_allowed(&self) -> bool106 fn queue_change_allowed(&self) -> bool; 107 108 /// Checks whether submitting something after this future grants access (exclusive or shared, 109 /// depending on the parameter) to the given buffer on the given queue. 110 /// 111 /// If the access is granted, returns the pipeline stage and access flags of the latest usage 112 /// of this resource, or `None` if irrelevant. 113 /// 114 /// > **Note**: Returning `Ok` means "access granted", while returning `Err` means 115 /// > "don't know". Therefore returning `Err` is never unsafe. check_buffer_access( &self, buffer: &dyn BufferAccess, exclusive: bool, queue: &Queue, ) -> Result<Option<(PipelineStages, AccessFlags)>, AccessCheckError>116 fn check_buffer_access( 117 &self, 118 buffer: &dyn BufferAccess, 119 exclusive: bool, 120 queue: &Queue, 121 ) -> Result<Option<(PipelineStages, AccessFlags)>, AccessCheckError>; 122 123 /// Checks whether submitting something after this future grants access (exclusive or shared, 124 /// depending on the parameter) to the given image on the given queue. 125 /// 126 /// If the access is granted, returns the pipeline stage and access flags of the latest usage 127 /// of this resource, or `None` if irrelevant. 128 /// 129 /// Implementations must ensure that the image is in the given layout. However if the `layout` 130 /// is `Undefined` then the implementation should accept any actual layout. 131 /// 132 /// > **Note**: Returning `Ok` means "access granted", while returning `Err` means 133 /// > "don't know". Therefore returning `Err` is never unsafe. 134 /// 135 /// > **Note**: Keep in mind that changing the layout of an image also requires exclusive 136 /// > access. check_image_access( &self, image: &dyn ImageAccess, layout: ImageLayout, exclusive: bool, queue: &Queue, ) -> Result<Option<(PipelineStages, AccessFlags)>, AccessCheckError>137 fn check_image_access( 138 &self, 139 image: &dyn ImageAccess, 140 layout: ImageLayout, 141 exclusive: bool, 142 queue: &Queue, 143 ) -> Result<Option<(PipelineStages, AccessFlags)>, AccessCheckError>; 144 145 /// Joins this future with another one, representing the moment when both events have happened. 146 // TODO: handle errors join<F>(self, other: F) -> JoinFuture<Self, F> where Self: Sized, F: GpuFuture,147 fn join<F>(self, other: F) -> JoinFuture<Self, F> 148 where 149 Self: Sized, 150 F: GpuFuture, 151 { 152 join::join(self, other) 153 } 154 155 /// Executes a command buffer after this future. 156 /// 157 /// > **Note**: This is just a shortcut function. The actual implementation is in the 158 /// > `CommandBuffer` trait. 159 #[inline] then_execute<Cb>( self, queue: Arc<Queue>, command_buffer: Cb, ) -> Result<CommandBufferExecFuture<Self, Cb>, CommandBufferExecError> where Self: Sized, Cb: PrimaryCommandBuffer + 'static,160 fn then_execute<Cb>( 161 self, 162 queue: Arc<Queue>, 163 command_buffer: Cb, 164 ) -> Result<CommandBufferExecFuture<Self, Cb>, CommandBufferExecError> 165 where 166 Self: Sized, 167 Cb: PrimaryCommandBuffer + 'static, 168 { 169 command_buffer.execute_after(self, queue) 170 } 171 172 /// Executes a command buffer after this future, on the same queue as the future. 173 /// 174 /// > **Note**: This is just a shortcut function. The actual implementation is in the 175 /// > `CommandBuffer` trait. 176 #[inline] then_execute_same_queue<Cb>( self, command_buffer: Cb, ) -> Result<CommandBufferExecFuture<Self, Cb>, CommandBufferExecError> where Self: Sized, Cb: PrimaryCommandBuffer + 'static,177 fn then_execute_same_queue<Cb>( 178 self, 179 command_buffer: Cb, 180 ) -> Result<CommandBufferExecFuture<Self, Cb>, CommandBufferExecError> 181 where 182 Self: Sized, 183 Cb: PrimaryCommandBuffer + 'static, 184 { 185 let queue = self.queue().unwrap().clone(); 186 command_buffer.execute_after(self, queue) 187 } 188 189 /// Signals a semaphore after this future. Returns another future that represents the signal. 190 /// 191 /// Call this function when you want to execute some operations on a queue and want to see the 192 /// result on another queue. 193 #[inline] then_signal_semaphore(self) -> SemaphoreSignalFuture<Self> where Self: Sized,194 fn then_signal_semaphore(self) -> SemaphoreSignalFuture<Self> 195 where 196 Self: Sized, 197 { 198 semaphore_signal::then_signal_semaphore(self) 199 } 200 201 /// Signals a semaphore after this future and flushes it. Returns another future that 202 /// represents the moment when the semaphore is signalled. 203 /// 204 /// This is a just a shortcut for `then_signal_semaphore()` followed with `flush()`. 205 /// 206 /// When you want to execute some operations A on a queue and some operations B on another 207 /// queue that need to see the results of A, it can be a good idea to submit A as soon as 208 /// possible while you're preparing B. 209 /// 210 /// If you ran A and B on the same queue, you would have to decide between submitting A then 211 /// B, or A and B simultaneously. Both approaches have their trade-offs. But if A and B are 212 /// on two different queues, then you would need two submits anyway and it is always 213 /// advantageous to submit A as soon as possible. 214 #[inline] then_signal_semaphore_and_flush(self) -> Result<SemaphoreSignalFuture<Self>, FlushError> where Self: Sized,215 fn then_signal_semaphore_and_flush(self) -> Result<SemaphoreSignalFuture<Self>, FlushError> 216 where 217 Self: Sized, 218 { 219 let f = self.then_signal_semaphore(); 220 f.flush()?; 221 Ok(f) 222 } 223 224 /// Signals a fence after this future. Returns another future that represents the signal. 225 /// 226 /// > **Note**: More often than not you want to immediately flush the future after calling this 227 /// > function. If so, consider using `then_signal_fence_and_flush`. 228 #[inline] then_signal_fence(self) -> FenceSignalFuture<Self> where Self: Sized,229 fn then_signal_fence(self) -> FenceSignalFuture<Self> 230 where 231 Self: Sized, 232 { 233 fence_signal::then_signal_fence(self, FenceSignalFutureBehavior::Continue) 234 } 235 236 /// Signals a fence after this future. Returns another future that represents the signal. 237 /// 238 /// This is a just a shortcut for `then_signal_fence()` followed with `flush()`. 239 #[inline] then_signal_fence_and_flush(self) -> Result<FenceSignalFuture<Self>, FlushError> where Self: Sized,240 fn then_signal_fence_and_flush(self) -> Result<FenceSignalFuture<Self>, FlushError> 241 where 242 Self: Sized, 243 { 244 let f = self.then_signal_fence(); 245 f.flush()?; 246 Ok(f) 247 } 248 249 /// Presents a swapchain image after this future. 250 /// 251 /// You should only ever do this indirectly after a `SwapchainAcquireFuture` of the same image, 252 /// otherwise an error will occur when flushing. 253 /// 254 /// > **Note**: This is just a shortcut for the `Swapchain::present()` function. 255 #[inline] then_swapchain_present<W>( self, queue: Arc<Queue>, swapchain: Arc<Swapchain<W>>, image_index: usize, ) -> PresentFuture<Self, W> where Self: Sized,256 fn then_swapchain_present<W>( 257 self, 258 queue: Arc<Queue>, 259 swapchain: Arc<Swapchain<W>>, 260 image_index: usize, 261 ) -> PresentFuture<Self, W> 262 where 263 Self: Sized, 264 { 265 swapchain::present(swapchain, self, queue, image_index) 266 } 267 268 /// Same as `then_swapchain_present`, except it allows specifying a present region. 269 /// 270 /// > **Note**: This is just a shortcut for the `Swapchain::present_incremental()` function. 271 #[inline] then_swapchain_present_incremental<W>( self, queue: Arc<Queue>, swapchain: Arc<Swapchain<W>>, image_index: usize, present_region: PresentRegion, ) -> PresentFuture<Self, W> where Self: Sized,272 fn then_swapchain_present_incremental<W>( 273 self, 274 queue: Arc<Queue>, 275 swapchain: Arc<Swapchain<W>>, 276 image_index: usize, 277 present_region: PresentRegion, 278 ) -> PresentFuture<Self, W> 279 where 280 Self: Sized, 281 { 282 swapchain::present_incremental(swapchain, self, queue, image_index, present_region) 283 } 284 285 /// Turn the current future into a `Box<dyn GpuFuture>`. 286 /// 287 /// This is a helper function that calls `Box::new(yourFuture) as Box<dyn GpuFuture>`. boxed(self) -> Box<dyn GpuFuture> where Self: Sized + 'static,288 fn boxed(self) -> Box<dyn GpuFuture> 289 where 290 Self: Sized + 'static, 291 { 292 Box::new(self) as _ 293 } 294 } 295 296 unsafe impl<F: ?Sized> GpuFuture for Box<F> 297 where 298 F: GpuFuture, 299 { 300 #[inline] cleanup_finished(&mut self)301 fn cleanup_finished(&mut self) { 302 (**self).cleanup_finished() 303 } 304 305 #[inline] build_submission(&self) -> Result<SubmitAnyBuilder, FlushError>306 unsafe fn build_submission(&self) -> Result<SubmitAnyBuilder, FlushError> { 307 (**self).build_submission() 308 } 309 310 #[inline] flush(&self) -> Result<(), FlushError>311 fn flush(&self) -> Result<(), FlushError> { 312 (**self).flush() 313 } 314 315 #[inline] signal_finished(&self)316 unsafe fn signal_finished(&self) { 317 (**self).signal_finished() 318 } 319 320 #[inline] queue_change_allowed(&self) -> bool321 fn queue_change_allowed(&self) -> bool { 322 (**self).queue_change_allowed() 323 } 324 325 #[inline] queue(&self) -> Option<Arc<Queue>>326 fn queue(&self) -> Option<Arc<Queue>> { 327 (**self).queue() 328 } 329 330 #[inline] check_buffer_access( &self, buffer: &dyn BufferAccess, exclusive: bool, queue: &Queue, ) -> Result<Option<(PipelineStages, AccessFlags)>, AccessCheckError>331 fn check_buffer_access( 332 &self, 333 buffer: &dyn BufferAccess, 334 exclusive: bool, 335 queue: &Queue, 336 ) -> Result<Option<(PipelineStages, AccessFlags)>, AccessCheckError> { 337 (**self).check_buffer_access(buffer, exclusive, queue) 338 } 339 340 #[inline] check_image_access( &self, image: &dyn ImageAccess, layout: ImageLayout, exclusive: bool, queue: &Queue, ) -> Result<Option<(PipelineStages, AccessFlags)>, AccessCheckError>341 fn check_image_access( 342 &self, 343 image: &dyn ImageAccess, 344 layout: ImageLayout, 345 exclusive: bool, 346 queue: &Queue, 347 ) -> Result<Option<(PipelineStages, AccessFlags)>, AccessCheckError> { 348 (**self).check_image_access(image, layout, exclusive, queue) 349 } 350 } 351 352 /// Access to a resource was denied. 353 #[derive(Clone, Debug, PartialEq, Eq)] 354 pub enum AccessError { 355 /// Exclusive access is denied. 356 ExclusiveDenied, 357 358 /// The resource is already in use, and there is no tracking of concurrent usages. 359 AlreadyInUse, 360 361 UnexpectedImageLayout { 362 allowed: ImageLayout, 363 requested: ImageLayout, 364 }, 365 366 /// Trying to use an image without transitioning it from the "undefined" or "preinitialized" 367 /// layouts first. 368 ImageNotInitialized { 369 /// The layout that was requested for the image. 370 requested: ImageLayout, 371 }, 372 373 /// Trying to use a buffer that still contains garbage data. 374 BufferNotInitialized, 375 376 /// Trying to use a swapchain image without depending on a corresponding acquire image future. 377 SwapchainImageAcquireOnly, 378 } 379 380 impl error::Error for AccessError {} 381 382 impl fmt::Display for AccessError { 383 #[inline] fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error>384 fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> { 385 write!( 386 fmt, 387 "{}", 388 match *self { 389 AccessError::ExclusiveDenied => "only shared access is allowed for this resource", 390 AccessError::AlreadyInUse => { 391 "the resource is already in use, and there is no tracking of concurrent usages" 392 } 393 AccessError::UnexpectedImageLayout { .. } => { 394 unimplemented!() // TODO: find a description 395 } 396 AccessError::ImageNotInitialized { .. } => { 397 "trying to use an image without transitioning it from the undefined or \ 398 preinitialized layouts first" 399 } 400 AccessError::BufferNotInitialized => { 401 "trying to use a buffer that still contains garbage data" 402 } 403 AccessError::SwapchainImageAcquireOnly => { 404 "trying to use a swapchain image without depending on a corresponding acquire \ 405 image future" 406 } 407 } 408 ) 409 } 410 } 411 412 /// Error that can happen when checking whether we have access to a resource. 413 #[derive(Clone, Debug, PartialEq, Eq)] 414 pub enum AccessCheckError { 415 /// Access to the resource has been denied. 416 Denied(AccessError), 417 /// The resource is unknown, therefore we cannot possibly answer whether we have access or not. 418 Unknown, 419 } 420 421 impl error::Error for AccessCheckError {} 422 423 impl fmt::Display for AccessCheckError { 424 #[inline] fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error>425 fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> { 426 write!( 427 fmt, 428 "{}", 429 match *self { 430 AccessCheckError::Denied(_) => "access to the resource has been denied", 431 AccessCheckError::Unknown => "the resource is unknown", 432 } 433 ) 434 } 435 } 436 437 impl From<AccessError> for AccessCheckError { 438 #[inline] from(err: AccessError) -> AccessCheckError439 fn from(err: AccessError) -> AccessCheckError { 440 AccessCheckError::Denied(err) 441 } 442 } 443 444 /// Error that can happen when creating a graphics pipeline. 445 #[derive(Clone, Debug, PartialEq, Eq)] 446 pub enum FlushError { 447 /// Access to a resource has been denied. 448 AccessError(AccessError), 449 450 /// Not enough memory. 451 OomError(OomError), 452 453 /// The connection to the device has been lost. 454 DeviceLost, 455 456 /// The surface is no longer accessible and must be recreated. 457 SurfaceLost, 458 459 /// The surface has changed in a way that makes the swapchain unusable. You must query the 460 /// surface's new properties and recreate a new swapchain if you want to continue drawing. 461 OutOfDate, 462 463 /// The swapchain has lost or doesn't have fullscreen exclusivity possibly for 464 /// implementation-specific reasons outside of the application’s control. 465 FullscreenExclusiveLost, 466 467 /// The flush operation needed to block, but the timeout has elapsed. 468 Timeout, 469 } 470 471 impl error::Error for FlushError { 472 #[inline] source(&self) -> Option<&(dyn error::Error + 'static)>473 fn source(&self) -> Option<&(dyn error::Error + 'static)> { 474 match *self { 475 FlushError::AccessError(ref err) => Some(err), 476 FlushError::OomError(ref err) => Some(err), 477 _ => None, 478 } 479 } 480 } 481 482 impl fmt::Display for FlushError { 483 #[inline] fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error>484 fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> { 485 write!( 486 fmt, 487 "{}", 488 match *self { 489 FlushError::AccessError(_) => "access to a resource has been denied", 490 FlushError::OomError(_) => "not enough memory", 491 FlushError::DeviceLost => "the connection to the device has been lost", 492 FlushError::SurfaceLost => "the surface of this swapchain is no longer valid", 493 FlushError::OutOfDate => "the swapchain needs to be recreated", 494 FlushError::FullscreenExclusiveLost => { 495 "the swapchain no longer has fullscreen exclusivity" 496 } 497 FlushError::Timeout => { 498 "the flush operation needed to block, but the timeout has \ 499 elapsed" 500 } 501 } 502 ) 503 } 504 } 505 506 impl From<AccessError> for FlushError { 507 #[inline] from(err: AccessError) -> FlushError508 fn from(err: AccessError) -> FlushError { 509 FlushError::AccessError(err) 510 } 511 } 512 513 impl From<SubmitPresentError> for FlushError { 514 #[inline] from(err: SubmitPresentError) -> FlushError515 fn from(err: SubmitPresentError) -> FlushError { 516 match err { 517 SubmitPresentError::OomError(err) => FlushError::OomError(err), 518 SubmitPresentError::DeviceLost => FlushError::DeviceLost, 519 SubmitPresentError::SurfaceLost => FlushError::SurfaceLost, 520 SubmitPresentError::OutOfDate => FlushError::OutOfDate, 521 SubmitPresentError::FullscreenExclusiveLost => FlushError::FullscreenExclusiveLost, 522 } 523 } 524 } 525 526 impl From<SubmitCommandBufferError> for FlushError { 527 #[inline] from(err: SubmitCommandBufferError) -> FlushError528 fn from(err: SubmitCommandBufferError) -> FlushError { 529 match err { 530 SubmitCommandBufferError::OomError(err) => FlushError::OomError(err), 531 SubmitCommandBufferError::DeviceLost => FlushError::DeviceLost, 532 } 533 } 534 } 535 536 impl From<SubmitBindSparseError> for FlushError { 537 #[inline] from(err: SubmitBindSparseError) -> FlushError538 fn from(err: SubmitBindSparseError) -> FlushError { 539 match err { 540 SubmitBindSparseError::OomError(err) => FlushError::OomError(err), 541 SubmitBindSparseError::DeviceLost => FlushError::DeviceLost, 542 } 543 } 544 } 545 546 impl From<FenceWaitError> for FlushError { 547 #[inline] from(err: FenceWaitError) -> FlushError548 fn from(err: FenceWaitError) -> FlushError { 549 match err { 550 FenceWaitError::OomError(err) => FlushError::OomError(err), 551 FenceWaitError::Timeout => FlushError::Timeout, 552 FenceWaitError::DeviceLostError => FlushError::DeviceLost, 553 } 554 } 555 } 556