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 super::{AccessCheckError, FlushError, GpuFuture, SubmitAnyBuilder};
11 use crate::{
12     buffer::Buffer,
13     device::{Device, DeviceOwned, Queue},
14     image::{sys::Image, ImageLayout},
15     swapchain::Swapchain,
16     DeviceSize, VulkanObject,
17 };
18 use std::{ops::Range, sync::Arc};
19 
20 /// Joins two futures together.
21 // TODO: handle errors
join<F, S>(first: F, second: S) -> JoinFuture<F, S> where F: GpuFuture, S: GpuFuture,22 pub fn join<F, S>(first: F, second: S) -> JoinFuture<F, S>
23 where
24     F: GpuFuture,
25     S: GpuFuture,
26 {
27     assert_eq!(first.device().handle(), second.device().handle());
28 
29     if !first.queue_change_allowed() && !second.queue_change_allowed() {
30         assert!(first.queue().unwrap() == second.queue().unwrap());
31     }
32 
33     JoinFuture { first, second }
34 }
35 
36 /// Two futures joined into one.
37 #[must_use]
38 pub struct JoinFuture<A, B> {
39     first: A,
40     second: B,
41 }
42 
43 unsafe impl<A, B> DeviceOwned for JoinFuture<A, B>
44 where
45     A: DeviceOwned,
46     B: DeviceOwned,
47 {
device(&self) -> &Arc<Device>48     fn device(&self) -> &Arc<Device> {
49         let device = self.first.device();
50         debug_assert_eq!(self.second.device().handle(), device.handle());
51         device
52     }
53 }
54 
55 unsafe impl<A, B> GpuFuture for JoinFuture<A, B>
56 where
57     A: GpuFuture,
58     B: GpuFuture,
59 {
cleanup_finished(&mut self)60     fn cleanup_finished(&mut self) {
61         self.first.cleanup_finished();
62         self.second.cleanup_finished();
63     }
64 
flush(&self) -> Result<(), FlushError>65     fn flush(&self) -> Result<(), FlushError> {
66         // Since each future remembers whether it has been flushed, there's no safety issue here
67         // if we call this function multiple times.
68         self.first.flush()?;
69         self.second.flush()?;
70 
71         Ok(())
72     }
73 
build_submission(&self) -> Result<SubmitAnyBuilder, FlushError>74     unsafe fn build_submission(&self) -> Result<SubmitAnyBuilder, FlushError> {
75         // TODO: review this function
76         let first = self.first.build_submission()?;
77         let second = self.second.build_submission()?;
78 
79         // In some cases below we have to submit previous command buffers already, this s done by flushing previous.
80         // Since the implementation should remember being flushed it's safe to call build_submission multiple times
81         Ok(match (first, second) {
82             (SubmitAnyBuilder::Empty, b) => b,
83             (a, SubmitAnyBuilder::Empty) => a,
84             (SubmitAnyBuilder::SemaphoresWait(mut a), SubmitAnyBuilder::SemaphoresWait(b)) => {
85                 a.extend(b);
86                 SubmitAnyBuilder::SemaphoresWait(a)
87             }
88             (SubmitAnyBuilder::SemaphoresWait(a), SubmitAnyBuilder::CommandBuffer(_, _)) => {
89                 self.second.flush()?;
90                 SubmitAnyBuilder::SemaphoresWait(a)
91             }
92             (SubmitAnyBuilder::CommandBuffer(_, _), SubmitAnyBuilder::SemaphoresWait(b)) => {
93                 self.first.flush()?;
94                 SubmitAnyBuilder::SemaphoresWait(b)
95             }
96             (SubmitAnyBuilder::SemaphoresWait(a), SubmitAnyBuilder::QueuePresent(_)) => {
97                 self.second.flush()?;
98                 SubmitAnyBuilder::SemaphoresWait(a)
99             }
100             (SubmitAnyBuilder::QueuePresent(_), SubmitAnyBuilder::SemaphoresWait(b)) => {
101                 self.first.flush()?;
102                 SubmitAnyBuilder::SemaphoresWait(b)
103             }
104             (SubmitAnyBuilder::SemaphoresWait(a), SubmitAnyBuilder::BindSparse(_, _)) => {
105                 self.second.flush()?;
106                 SubmitAnyBuilder::SemaphoresWait(a)
107             }
108             (SubmitAnyBuilder::BindSparse(_, _), SubmitAnyBuilder::SemaphoresWait(b)) => {
109                 self.first.flush()?;
110                 SubmitAnyBuilder::SemaphoresWait(b)
111             }
112             (
113                 SubmitAnyBuilder::CommandBuffer(mut submit_info_a, fence_a),
114                 SubmitAnyBuilder::CommandBuffer(submit_info_b, fence_b),
115             ) => {
116                 assert!(
117                     fence_a.is_none() || fence_b.is_none(),
118                     "Can't merge two queue submits that both have a fence"
119                 );
120 
121                 submit_info_a
122                     .wait_semaphores
123                     .extend(submit_info_b.wait_semaphores);
124                 submit_info_a
125                     .command_buffers
126                     .extend(submit_info_b.command_buffers);
127                 submit_info_a
128                     .signal_semaphores
129                     .extend(submit_info_b.signal_semaphores);
130 
131                 SubmitAnyBuilder::CommandBuffer(submit_info_a, fence_a.or(fence_b))
132             }
133             (SubmitAnyBuilder::QueuePresent(_), SubmitAnyBuilder::QueuePresent(_)) => {
134                 self.first.flush()?;
135                 self.second.flush()?;
136                 SubmitAnyBuilder::Empty
137             }
138             (SubmitAnyBuilder::CommandBuffer(_, _), SubmitAnyBuilder::QueuePresent(_)) => {
139                 unimplemented!()
140             }
141             (SubmitAnyBuilder::QueuePresent(_), SubmitAnyBuilder::CommandBuffer(_, _)) => {
142                 unimplemented!()
143             }
144             (SubmitAnyBuilder::BindSparse(_, _), SubmitAnyBuilder::QueuePresent(_)) => {
145                 unimplemented!()
146             }
147             (SubmitAnyBuilder::QueuePresent(_), SubmitAnyBuilder::BindSparse(_, _)) => {
148                 unimplemented!()
149             }
150             (SubmitAnyBuilder::BindSparse(_, _), SubmitAnyBuilder::CommandBuffer(_, _)) => {
151                 unimplemented!()
152             }
153             (SubmitAnyBuilder::CommandBuffer(_, _), SubmitAnyBuilder::BindSparse(_, _)) => {
154                 unimplemented!()
155             }
156             (
157                 SubmitAnyBuilder::BindSparse(mut bind_infos_a, fence_a),
158                 SubmitAnyBuilder::BindSparse(bind_infos_b, fence_b),
159             ) => {
160                 if fence_a.is_some() && fence_b.is_some() {
161                     // TODO: this happens if both bind sparse have been given a fence already
162                     //       annoying, but not impossible, to handle
163                     unimplemented!()
164                 }
165 
166                 bind_infos_a.extend(bind_infos_b);
167                 SubmitAnyBuilder::BindSparse(bind_infos_a, fence_a)
168             }
169         })
170     }
171 
signal_finished(&self)172     unsafe fn signal_finished(&self) {
173         self.first.signal_finished();
174         self.second.signal_finished();
175     }
176 
queue_change_allowed(&self) -> bool177     fn queue_change_allowed(&self) -> bool {
178         self.first.queue_change_allowed() && self.second.queue_change_allowed()
179     }
180 
queue(&self) -> Option<Arc<Queue>>181     fn queue(&self) -> Option<Arc<Queue>> {
182         match (self.first.queue(), self.second.queue()) {
183             (Some(q1), Some(q2)) => {
184                 if q1 == q2 {
185                     Some(q1)
186                 } else if self.first.queue_change_allowed() {
187                     Some(q2)
188                 } else if self.second.queue_change_allowed() {
189                     Some(q1)
190                 } else {
191                     None
192                 }
193             }
194             (Some(q), None) => Some(q),
195             (None, Some(q)) => Some(q),
196             (None, None) => None,
197         }
198     }
199 
check_buffer_access( &self, buffer: &Buffer, range: Range<DeviceSize>, exclusive: bool, queue: &Queue, ) -> Result<(), AccessCheckError>200     fn check_buffer_access(
201         &self,
202         buffer: &Buffer,
203         range: Range<DeviceSize>,
204         exclusive: bool,
205         queue: &Queue,
206     ) -> Result<(), AccessCheckError> {
207         let first = self
208             .first
209             .check_buffer_access(buffer, range.clone(), exclusive, queue);
210         let second = self
211             .second
212             .check_buffer_access(buffer, range, exclusive, queue);
213         debug_assert!(
214             !(exclusive && first.is_ok() && second.is_ok()),
215             "Two futures gave exclusive access to the same resource"
216         );
217         match (first, second) {
218             (v, Err(AccessCheckError::Unknown)) => v,
219             (Err(AccessCheckError::Unknown), v) => v,
220             (Err(AccessCheckError::Denied(e1)), Err(AccessCheckError::Denied(_))) => {
221                 Err(AccessCheckError::Denied(e1))
222             } // TODO: which one?
223             (Ok(()), Err(AccessCheckError::Denied(_)))
224             | (Err(AccessCheckError::Denied(_)), Ok(())) => panic!(
225                 "Contradictory information \
226                                                                  between two futures"
227             ),
228             (Ok(()), Ok(())) => Ok(()),
229         }
230     }
231 
check_image_access( &self, image: &Image, range: Range<DeviceSize>, exclusive: bool, expected_layout: ImageLayout, queue: &Queue, ) -> Result<(), AccessCheckError>232     fn check_image_access(
233         &self,
234         image: &Image,
235         range: Range<DeviceSize>,
236         exclusive: bool,
237         expected_layout: ImageLayout,
238         queue: &Queue,
239     ) -> Result<(), AccessCheckError> {
240         let first =
241             self.first
242                 .check_image_access(image, range.clone(), exclusive, expected_layout, queue);
243         let second =
244             self.second
245                 .check_image_access(image, range, exclusive, expected_layout, queue);
246         debug_assert!(
247             !(exclusive && first.is_ok() && second.is_ok()),
248             "Two futures gave exclusive access to the same resource"
249         );
250         match (first, second) {
251             (v, Err(AccessCheckError::Unknown)) => v,
252             (Err(AccessCheckError::Unknown), v) => v,
253             (Err(AccessCheckError::Denied(e1)), Err(AccessCheckError::Denied(_))) => {
254                 Err(AccessCheckError::Denied(e1))
255             } // TODO: which one?
256             (Ok(()), Err(AccessCheckError::Denied(_)))
257             | (Err(AccessCheckError::Denied(_)), Ok(())) => {
258                 panic!("Contradictory information between two futures")
259             }
260             (Ok(()), Ok(())) => Ok(()),
261         }
262     }
263 
264     #[inline]
check_swapchain_image_acquired( &self, swapchain: &Swapchain, image_index: u32, _before: bool, ) -> Result<(), AccessCheckError>265     fn check_swapchain_image_acquired(
266         &self,
267         swapchain: &Swapchain,
268         image_index: u32,
269         _before: bool,
270     ) -> Result<(), AccessCheckError> {
271         let first = self
272             .first
273             .check_swapchain_image_acquired(swapchain, image_index, false);
274         let second = self
275             .second
276             .check_swapchain_image_acquired(swapchain, image_index, false);
277 
278         match (first, second) {
279             (v, Err(AccessCheckError::Unknown)) => v,
280             (Err(AccessCheckError::Unknown), v) => v,
281             (Err(AccessCheckError::Denied(e1)), Err(AccessCheckError::Denied(_))) => {
282                 Err(AccessCheckError::Denied(e1))
283             } // TODO: which one?
284             (Ok(()), Err(AccessCheckError::Denied(_)))
285             | (Err(AccessCheckError::Denied(_)), Ok(())) => Ok(()),
286             (Ok(()), Ok(())) => Ok(()), // TODO: Double Acquired?
287         }
288     }
289 }
290