1 // Copyright (c) 2017 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::sys::UnsafeBuffer; 11 use crate::check_errors; 12 use crate::device::Queue; 13 use crate::image::sys::UnsafeImage; 14 use crate::memory::DeviceMemory; 15 use crate::sync::Fence; 16 use crate::sync::Semaphore; 17 use crate::DeviceSize; 18 use crate::Error; 19 use crate::OomError; 20 use crate::SynchronizedVulkanObject; 21 use crate::VulkanObject; 22 use smallvec::SmallVec; 23 use std::error; 24 use std::fmt; 25 use std::marker::PhantomData; 26 27 // TODO: correctly implement Debug on all the structs of this module 28 29 /// Prototype for a submission that binds sparse memory. 30 // TODO: example here 31 pub struct SubmitBindSparseBuilder<'a> { 32 infos: SmallVec<[SubmitBindSparseBatchBuilder<'a>; 1]>, 33 fence: ash::vk::Fence, 34 } 35 36 impl<'a> SubmitBindSparseBuilder<'a> { 37 /// Builds a new empty `SubmitBindSparseBuilder`. 38 #[inline] new() -> SubmitBindSparseBuilder<'a>39 pub fn new() -> SubmitBindSparseBuilder<'a> { 40 SubmitBindSparseBuilder { 41 infos: SmallVec::new(), 42 fence: ash::vk::Fence::null(), 43 } 44 } 45 46 /// Adds a batch to the command. 47 /// 48 /// Batches start execution in order, but can finish in a different order. In other words any 49 /// wait semaphore added to a batch will apply to further batches as well, but when a semaphore 50 /// is signalled, it does **not** mean that previous batches have been completed. 51 #[inline] add(&mut self, builder: SubmitBindSparseBatchBuilder<'a>)52 pub fn add(&mut self, builder: SubmitBindSparseBatchBuilder<'a>) { 53 self.infos.push(builder); 54 } 55 56 /// Returns true if this builder will signal a fence when submitted. 57 /// 58 /// # Example 59 /// 60 /// ``` 61 /// use vulkano::command_buffer::submit::SubmitBindSparseBuilder; 62 /// use vulkano::sync::Fence; 63 /// # let device: std::sync::Arc<vulkano::device::Device> = return; 64 /// 65 /// unsafe { 66 /// let fence = Fence::from_pool(device.clone()).unwrap(); 67 /// 68 /// let mut builder = SubmitBindSparseBuilder::new(); 69 /// assert!(!builder.has_fence()); 70 /// builder.set_fence_signal(&fence); 71 /// assert!(builder.has_fence()); 72 /// } 73 /// ``` 74 #[inline] has_fence(&self) -> bool75 pub fn has_fence(&self) -> bool { 76 self.fence != ash::vk::Fence::null() 77 } 78 79 /// Adds an operation that signals a fence after this submission ends. 80 /// 81 /// # Example 82 /// 83 /// ``` 84 /// use std::time::Duration; 85 /// use vulkano::command_buffer::submit::SubmitBindSparseBuilder; 86 /// use vulkano::sync::Fence; 87 /// # let device: std::sync::Arc<vulkano::device::Device> = return; 88 /// # let queue: std::sync::Arc<vulkano::device::Queue> = return; 89 /// 90 /// unsafe { 91 /// let fence = Fence::from_pool(device.clone()).unwrap(); 92 /// 93 /// let mut builder = SubmitBindSparseBuilder::new(); 94 /// builder.set_fence_signal(&fence); 95 /// 96 /// builder.submit(&queue).unwrap(); 97 /// 98 /// // We must not destroy the fence before it is signaled. 99 /// fence.wait(None).unwrap(); 100 /// } 101 /// ``` 102 /// 103 /// # Safety 104 /// 105 /// - The fence must not be signaled at the time when you call `submit()`. 106 /// 107 /// - If you use the fence for multiple submissions, only one at a time must be executed by the 108 /// GPU. In other words, you must submit one, wait for the fence to be signaled, then reset 109 /// the fence, and then only submit the second. 110 /// 111 /// - If you submit this builder, the fence must be kept alive until it is signaled by the GPU. 112 /// Destroying the fence earlier is an undefined behavior. 113 /// 114 /// - The fence, buffers, images, and semaphores must all belong to the same device. 115 /// 116 #[inline] set_fence_signal(&mut self, fence: &'a Fence)117 pub unsafe fn set_fence_signal(&mut self, fence: &'a Fence) { 118 self.fence = fence.internal_object(); 119 } 120 121 /// Attempts to merge this builder with another one. 122 /// 123 /// If both builders have a fence already set, then this function will return `other` as an 124 /// error. 125 #[inline] merge( &mut self, other: SubmitBindSparseBuilder<'a>, ) -> Result<(), SubmitBindSparseBuilder<'a>>126 pub fn merge( 127 &mut self, 128 other: SubmitBindSparseBuilder<'a>, 129 ) -> Result<(), SubmitBindSparseBuilder<'a>> { 130 if self.fence != ash::vk::Fence::null() && other.fence != ash::vk::Fence::null() { 131 return Err(other); 132 } 133 134 self.infos.extend(other.infos.into_iter()); 135 Ok(()) 136 } 137 138 /// Submits the command. Calls `vkQueueBindSparse`. submit(self, queue: &Queue) -> Result<(), SubmitBindSparseError>139 pub fn submit(self, queue: &Queue) -> Result<(), SubmitBindSparseError> { 140 unsafe { 141 debug_assert!(queue.family().supports_sparse_binding()); 142 143 let fns = queue.device().fns(); 144 let queue = queue.internal_object_guard(); 145 146 // We start by storing all the `VkSparseBufferMemoryBindInfo`s of the whole command 147 // in the same collection. 148 let buffer_binds_storage: SmallVec<[_; 4]> = self 149 .infos 150 .iter() 151 .flat_map(|infos| infos.buffer_binds.iter()) 152 .map(|buf_bind| ash::vk::SparseBufferMemoryBindInfo { 153 buffer: buf_bind.buffer, 154 bind_count: buf_bind.binds.len() as u32, 155 p_binds: buf_bind.binds.as_ptr(), 156 }) 157 .collect(); 158 159 // Same for all the `VkSparseImageOpaqueMemoryBindInfo`s. 160 let image_opaque_binds_storage: SmallVec<[_; 4]> = self 161 .infos 162 .iter() 163 .flat_map(|infos| infos.image_opaque_binds.iter()) 164 .map(|img_bind| ash::vk::SparseImageOpaqueMemoryBindInfo { 165 image: img_bind.image, 166 bind_count: img_bind.binds.len() as u32, 167 p_binds: img_bind.binds.as_ptr(), 168 }) 169 .collect(); 170 171 // And finally the `VkSparseImageMemoryBindInfo`s. 172 let image_binds_storage: SmallVec<[_; 4]> = self 173 .infos 174 .iter() 175 .flat_map(|infos| infos.image_binds.iter()) 176 .map(|img_bind| ash::vk::SparseImageMemoryBindInfo { 177 image: img_bind.image, 178 bind_count: img_bind.binds.len() as u32, 179 p_binds: img_bind.binds.as_ptr(), 180 }) 181 .collect(); 182 183 // Now building the collection of `VkBindSparseInfo`s. 184 let bs_infos = { 185 let mut bs_infos: SmallVec<[_; 4]> = SmallVec::new(); 186 187 // Since we stores all the bind infos contiguously, we keep track of the current 188 // offset within these containers. 189 let mut next_buffer_bind = 0; 190 let mut next_image_opaque_bind = 0; 191 let mut next_image_bind = 0; 192 193 for builder in self.infos.iter() { 194 bs_infos.push(ash::vk::BindSparseInfo { 195 wait_semaphore_count: builder.wait_semaphores.len() as u32, 196 p_wait_semaphores: builder.wait_semaphores.as_ptr(), 197 buffer_bind_count: builder.buffer_binds.len() as u32, 198 p_buffer_binds: if next_buffer_bind != 0 { 199 // We need that `if` because `.as_ptr().offset(0)` is technically UB. 200 buffer_binds_storage.as_ptr().offset(next_buffer_bind) 201 } else { 202 buffer_binds_storage.as_ptr() 203 }, 204 image_opaque_bind_count: builder.image_opaque_binds.len() as u32, 205 p_image_opaque_binds: if next_image_opaque_bind != 0 { 206 // We need that `if` because `.as_ptr().offset(0)` is technically UB. 207 image_opaque_binds_storage 208 .as_ptr() 209 .offset(next_image_opaque_bind) 210 } else { 211 image_opaque_binds_storage.as_ptr() 212 }, 213 image_bind_count: builder.image_binds.len() as u32, 214 p_image_binds: if next_image_bind != 0 { 215 // We need that `if` because `.as_ptr().offset(0)` is technically UB. 216 image_binds_storage.as_ptr().offset(next_image_bind) 217 } else { 218 image_binds_storage.as_ptr() 219 }, 220 signal_semaphore_count: builder.signal_semaphores.len() as u32, 221 p_signal_semaphores: builder.signal_semaphores.as_ptr(), 222 ..Default::default() 223 }); 224 225 next_buffer_bind += builder.buffer_binds.len() as isize; 226 next_image_opaque_bind += builder.image_opaque_binds.len() as isize; 227 next_image_bind += builder.image_binds.len() as isize; 228 } 229 230 // If these assertions fail, then there's something wrong in the code above. 231 debug_assert_eq!(next_buffer_bind as usize, buffer_binds_storage.len()); 232 debug_assert_eq!( 233 next_image_opaque_bind as usize, 234 image_opaque_binds_storage.len() 235 ); 236 debug_assert_eq!(next_image_bind as usize, image_binds_storage.len()); 237 238 bs_infos 239 }; 240 241 // Finally executing the command. 242 check_errors(fns.v1_0.queue_bind_sparse( 243 *queue, 244 bs_infos.len() as u32, 245 bs_infos.as_ptr(), 246 self.fence, 247 ))?; 248 Ok(()) 249 } 250 } 251 } 252 253 impl<'a> fmt::Debug for SubmitBindSparseBuilder<'a> { 254 #[inline] fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error>255 fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> { 256 write!(fmt, "<Bind sparse operation>") 257 } 258 } 259 260 /// A single batch of a sparse bind operation. 261 pub struct SubmitBindSparseBatchBuilder<'a> { 262 wait_semaphores: SmallVec<[ash::vk::Semaphore; 8]>, 263 buffer_binds: SmallVec<[SubmitBindSparseBufferBindBuilder<'a>; 2]>, 264 image_opaque_binds: SmallVec<[SubmitBindSparseImageOpaqueBindBuilder<'a>; 2]>, 265 image_binds: SmallVec<[SubmitBindSparseImageBindBuilder<'a>; 2]>, 266 signal_semaphores: SmallVec<[ash::vk::Semaphore; 8]>, 267 marker: PhantomData<&'a ()>, 268 } 269 270 impl<'a> SubmitBindSparseBatchBuilder<'a> { 271 /// Builds a new empty `SubmitBindSparseBatchBuilder`. 272 #[inline] new() -> SubmitBindSparseBatchBuilder<'a>273 pub fn new() -> SubmitBindSparseBatchBuilder<'a> { 274 SubmitBindSparseBatchBuilder { 275 wait_semaphores: SmallVec::new(), 276 buffer_binds: SmallVec::new(), 277 image_opaque_binds: SmallVec::new(), 278 image_binds: SmallVec::new(), 279 signal_semaphores: SmallVec::new(), 280 marker: PhantomData, 281 } 282 } 283 284 /// Adds an operation that binds memory to a buffer. add_buffer(&mut self, cmd: SubmitBindSparseBufferBindBuilder<'a>)285 pub fn add_buffer(&mut self, cmd: SubmitBindSparseBufferBindBuilder<'a>) { 286 self.buffer_binds.push(cmd); 287 } 288 289 /// Adds an operation that binds memory to an opaque image. add_image_opaque(&mut self, cmd: SubmitBindSparseImageOpaqueBindBuilder<'a>)290 pub fn add_image_opaque(&mut self, cmd: SubmitBindSparseImageOpaqueBindBuilder<'a>) { 291 self.image_opaque_binds.push(cmd); 292 } 293 294 /// Adds an operation that binds memory to an image. add_image(&mut self, cmd: SubmitBindSparseImageBindBuilder<'a>)295 pub fn add_image(&mut self, cmd: SubmitBindSparseImageBindBuilder<'a>) { 296 self.image_binds.push(cmd); 297 } 298 299 /// Adds a semaphore to be waited upon before the sparse binding is executed. 300 /// 301 /// # Safety 302 /// 303 /// - If you submit this builder, the semaphore must be kept alive until you are guaranteed 304 /// that the GPU has at least started executing the operation. 305 /// 306 /// - If you submit this builder, no other queue must be waiting on these semaphores. In other 307 /// words, each semaphore signal can only correspond to one semaphore wait. 308 /// 309 /// - If you submit this builder, the semaphores must be signaled when the queue execution 310 /// reaches this submission, or there must be one or more submissions in queues that are 311 /// going to signal these semaphores. In other words, you must not block the queue with 312 /// semaphores that can't get signaled. 313 /// 314 /// - The fence, buffers, images, and semaphores must all belong to the same device. 315 /// 316 #[inline] add_wait_semaphore(&mut self, semaphore: &'a Semaphore)317 pub unsafe fn add_wait_semaphore(&mut self, semaphore: &'a Semaphore) { 318 self.wait_semaphores.push(semaphore.internal_object()); 319 } 320 321 /// Returns the number of semaphores to signal. 322 /// 323 /// In other words, this is the number of times `add_signal_semaphore` has been called. 324 #[inline] num_signal_semaphores(&self) -> usize325 pub fn num_signal_semaphores(&self) -> usize { 326 self.signal_semaphores.len() 327 } 328 329 /// Adds a semaphore that is going to be signaled at the end of the submission. 330 /// 331 /// # Safety 332 /// 333 /// - If you submit this builder, the semaphore must be kept alive until you are guaranteed 334 /// that the GPU has finished executing this submission. 335 /// 336 /// - The semaphore must be in the unsignaled state when queue execution reaches this 337 /// submission. 338 /// 339 /// - The fence, buffers, images, and semaphores must all belong to the same device. 340 /// 341 #[inline] add_signal_semaphore(&mut self, semaphore: &'a Semaphore)342 pub unsafe fn add_signal_semaphore(&mut self, semaphore: &'a Semaphore) { 343 self.signal_semaphores.push(semaphore.internal_object()); 344 } 345 } 346 347 pub struct SubmitBindSparseBufferBindBuilder<'a> { 348 buffer: ash::vk::Buffer, 349 binds: SmallVec<[ash::vk::SparseMemoryBind; 1]>, 350 marker: PhantomData<&'a ()>, 351 } 352 353 impl<'a> SubmitBindSparseBufferBindBuilder<'a> { 354 /// 355 /// # Safety 356 /// 357 /// - `buffer` must be a buffer with sparse binding enabled. new(buffer: &'a UnsafeBuffer) -> SubmitBindSparseBufferBindBuilder358 pub unsafe fn new(buffer: &'a UnsafeBuffer) -> SubmitBindSparseBufferBindBuilder { 359 SubmitBindSparseBufferBindBuilder { 360 buffer: buffer.internal_object(), 361 binds: SmallVec::new(), 362 marker: PhantomData, 363 } 364 } 365 add_bind( &mut self, offset: DeviceSize, size: DeviceSize, memory: &DeviceMemory, memory_offset: DeviceSize, )366 pub unsafe fn add_bind( 367 &mut self, 368 offset: DeviceSize, 369 size: DeviceSize, 370 memory: &DeviceMemory, 371 memory_offset: DeviceSize, 372 ) { 373 self.binds.push(ash::vk::SparseMemoryBind { 374 resource_offset: offset, 375 size, 376 memory: memory.internal_object(), 377 memory_offset, 378 flags: ash::vk::SparseMemoryBindFlags::empty(), // Flags are only relevant for images. 379 }); 380 } 381 add_unbind(&mut self, offset: DeviceSize, size: DeviceSize)382 pub unsafe fn add_unbind(&mut self, offset: DeviceSize, size: DeviceSize) { 383 self.binds.push(ash::vk::SparseMemoryBind { 384 resource_offset: offset, 385 size, 386 memory: ash::vk::DeviceMemory::null(), 387 memory_offset: 0, 388 flags: ash::vk::SparseMemoryBindFlags::empty(), 389 }); 390 } 391 } 392 393 pub struct SubmitBindSparseImageOpaqueBindBuilder<'a> { 394 image: ash::vk::Image, 395 binds: SmallVec<[ash::vk::SparseMemoryBind; 1]>, 396 marker: PhantomData<&'a ()>, 397 } 398 399 impl<'a> SubmitBindSparseImageOpaqueBindBuilder<'a> { 400 /// 401 /// # Safety 402 /// 403 /// - `image` must be an image with sparse binding enabled. new(image: &'a UnsafeImage) -> SubmitBindSparseImageOpaqueBindBuilder404 pub unsafe fn new(image: &'a UnsafeImage) -> SubmitBindSparseImageOpaqueBindBuilder { 405 SubmitBindSparseImageOpaqueBindBuilder { 406 image: image.internal_object(), 407 binds: SmallVec::new(), 408 marker: PhantomData, 409 } 410 } 411 add_bind( &mut self, offset: DeviceSize, size: DeviceSize, memory: &DeviceMemory, memory_offset: DeviceSize, bind_metadata: bool, )412 pub unsafe fn add_bind( 413 &mut self, 414 offset: DeviceSize, 415 size: DeviceSize, 416 memory: &DeviceMemory, 417 memory_offset: DeviceSize, 418 bind_metadata: bool, 419 ) { 420 self.binds.push(ash::vk::SparseMemoryBind { 421 resource_offset: offset, 422 size, 423 memory: memory.internal_object(), 424 memory_offset, 425 flags: if bind_metadata { 426 ash::vk::SparseMemoryBindFlags::METADATA 427 } else { 428 ash::vk::SparseMemoryBindFlags::empty() 429 }, 430 }); 431 } 432 add_unbind(&mut self, offset: DeviceSize, size: DeviceSize)433 pub unsafe fn add_unbind(&mut self, offset: DeviceSize, size: DeviceSize) { 434 self.binds.push(ash::vk::SparseMemoryBind { 435 resource_offset: offset, 436 size, 437 memory: ash::vk::DeviceMemory::null(), 438 memory_offset: 0, 439 flags: ash::vk::SparseMemoryBindFlags::empty(), // TODO: is that relevant? 440 }); 441 } 442 } 443 444 pub struct SubmitBindSparseImageBindBuilder<'a> { 445 image: ash::vk::Image, 446 binds: SmallVec<[ash::vk::SparseImageMemoryBind; 1]>, 447 marker: PhantomData<&'a ()>, 448 } 449 450 impl<'a> SubmitBindSparseImageBindBuilder<'a> { 451 /// 452 /// # Safety 453 /// 454 /// - `image` must be an image with sparse binding enabled. new(image: &'a UnsafeImage) -> SubmitBindSparseImageBindBuilder455 pub unsafe fn new(image: &'a UnsafeImage) -> SubmitBindSparseImageBindBuilder { 456 SubmitBindSparseImageBindBuilder { 457 image: image.internal_object(), 458 binds: SmallVec::new(), 459 marker: PhantomData, 460 } 461 } 462 463 // TODO: finish 464 } 465 466 /// Error that can happen when submitting the present prototype. 467 #[derive(Copy, Clone, Debug, PartialEq, Eq)] 468 #[repr(u32)] 469 pub enum SubmitBindSparseError { 470 /// Not enough memory. 471 OomError(OomError), 472 473 /// The connection to the device has been lost. 474 DeviceLost, 475 } 476 477 impl error::Error for SubmitBindSparseError { 478 #[inline] source(&self) -> Option<&(dyn error::Error + 'static)>479 fn source(&self) -> Option<&(dyn error::Error + 'static)> { 480 match *self { 481 SubmitBindSparseError::OomError(ref err) => Some(err), 482 _ => None, 483 } 484 } 485 } 486 487 impl fmt::Display for SubmitBindSparseError { 488 #[inline] fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error>489 fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> { 490 write!( 491 fmt, 492 "{}", 493 match *self { 494 SubmitBindSparseError::OomError(_) => "not enough memory", 495 SubmitBindSparseError::DeviceLost => "the connection to the device has been lost", 496 } 497 ) 498 } 499 } 500 501 impl From<Error> for SubmitBindSparseError { 502 #[inline] from(err: Error) -> SubmitBindSparseError503 fn from(err: Error) -> SubmitBindSparseError { 504 match err { 505 err @ Error::OutOfHostMemory => SubmitBindSparseError::OomError(OomError::from(err)), 506 err @ Error::OutOfDeviceMemory => SubmitBindSparseError::OomError(OomError::from(err)), 507 Error::DeviceLost => SubmitBindSparseError::DeviceLost, 508 _ => panic!("unexpected error: {:?}", err), 509 } 510 } 511 } 512