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