glium/buffer/
fences.rs

1/*!
2
3This module handles the fences of a buffer.
4
5*/
6use smallvec::SmallVec;
7use std::cell::RefCell;
8use std::ops::Range;
9
10use crate::context::CommandContext;
11use crate::sync::{self, LinearSyncFence};
12
13/// Contains a list of fences.
14pub struct Fences {
15    fences: RefCell<SmallVec<[(Range<usize>, LinearSyncFence); 16]>>,
16}
17
18impl Fences {
19    /// Initialization.
20    pub fn new() -> Fences {
21        Fences {
22            fences: RefCell::new(SmallVec::new()),
23        }
24    }
25
26    /// Creates an `Inserter` that allows inserting a fence in the list for the given range.
27    #[inline]
28    pub fn inserter(&self, range: Range<usize>) -> Inserter<'_> {
29        Inserter {
30            fences: self,
31            range,
32        }
33    }
34
35    /// Waits until the given range is accessible.
36    pub fn wait(&self, ctxt: &mut CommandContext<'_>, range: Range<usize>) {
37        let mut existing_fences = self.fences.borrow_mut();
38        let mut new_fences = SmallVec::new();
39
40        for existing in existing_fences.drain(..) {
41            if (existing.0.start >= range.start && existing.0.start < range.end) ||
42               (existing.0.end > range.start && existing.0.end < range.end)
43            {
44                unsafe { sync::wait_linear_sync_fence_and_drop(existing.1, ctxt) };
45            } else {
46                new_fences.push(existing);
47            }
48        }
49
50        *existing_fences = new_fences;
51    }
52
53    /// Cleans up all fences in the container. Must be called or you'll get a panic.
54    pub fn clean(&mut self, ctxt: &mut CommandContext<'_>) {
55        let mut fences = self.fences.borrow_mut();
56        for (_, sync) in fences.drain(..) {
57            unsafe { sync::destroy_linear_sync_fence(ctxt, sync) };
58        }
59    }
60}
61
62/// Allows inserting a fence in the list.
63pub struct Inserter<'a> {
64    fences: &'a Fences,
65    range: Range<usize>,
66}
67
68impl<'a> Inserter<'a> {
69    /// Inserts a new fence.
70    pub fn insert(self, ctxt: &mut CommandContext<'_>) {
71        let mut new_fences = SmallVec::new();
72
73        let mut written = false;
74
75        let mut existing_fences = self.fences.fences.borrow_mut();
76        for existing in existing_fences.drain(..) {
77            if existing.0.start < self.range.start && existing.0.end <= self.range.start {
78                new_fences.push(existing);
79
80            } else if existing.0.start < self.range.start && existing.0.end >= self.range.end {
81                // we are stuck here, because we can't duplicate a fence
82                // so instead we just extend the new fence to the existing one
83                let new_fence = unsafe { sync::new_linear_sync_fence(ctxt).unwrap() };
84                new_fences.push((existing.0.start .. self.range.start, existing.1));
85                new_fences.push((self.range.start .. existing.0.end, new_fence));
86                written = true;
87
88            } else if existing.0.start < self.range.start && existing.0.end >= self.range.start {
89                new_fences.push((existing.0.start .. self.range.start, existing.1));
90                if !written {
91                    let new_fence = unsafe { sync::new_linear_sync_fence(ctxt).unwrap() };
92                    new_fences.push((self.range.clone(), new_fence));
93                    written = true;
94                }
95
96            } else if existing.0.start >= self.range.start && existing.0.end <= self.range.end {
97                unsafe { sync::destroy_linear_sync_fence(ctxt, existing.1) };
98                if !written {
99                    let new_fence = unsafe { sync::new_linear_sync_fence(ctxt).unwrap() };
100                    new_fences.push((self.range.clone(), new_fence));
101                    written = true;
102                }
103
104            } else if existing.0.start >= self.range.end {
105                if !written {
106                    let new_fence = unsafe { sync::new_linear_sync_fence(ctxt).unwrap() };
107                    new_fences.push((self.range.clone(), new_fence));
108                    written = true;
109                }
110
111                new_fences.push(existing);
112
113            } else {
114                if !written {
115                    let new_fence = unsafe { sync::new_linear_sync_fence(ctxt).unwrap() };
116                    new_fences.push((self.range.clone(), new_fence));
117                    written = true;
118                }
119
120                new_fences.push((self.range.end .. existing.0.end, existing.1));
121            }
122        }
123
124        if !written {
125            let new_fence = unsafe { sync::new_linear_sync_fence(ctxt).unwrap() };
126            new_fences.push((self.range, new_fence));
127        }
128
129        *existing_fences = new_fences;
130    }
131}