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