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