• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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