rp_cvideo_core/
display_buffer.rs

1#[cfg(test)]
2#[path = "../test/test_display_buffer.rs"]
3mod tests;
4
5use core::marker::PhantomData;
6
7/// DisplayBuffer
8///
9/// Contains either one or two fields. In case of progressive video, a field is just the same as the
10/// whole frame. In case of interlaced, it's the image from either the odd or even lines.
11pub struct DisplayBuffer<'t, FieldCount: NoFields> {
12    pub(crate) buffer: &'t mut [u32],
13
14    /// The index in `buffer` where the pixel data starts.
15    /// The second value in the array is for the odd-field in case of an interlaced buffer.
16    /// In case of a progressive display buffer, you should ignore the second value in the array.
17    pub(crate) buffer_pixel_offsets: [usize; 2],
18
19    /// The number of pixels horizontally
20    pub columns: u32,
21
22    /// The number of pixels vertically
23    pub lines: u32,
24
25    /// The distance in number of words between each row of pixels
26    pub(crate) stride: usize,
27
28    pub(crate) _fc: PhantomData<FieldCount>,
29}
30
31trait Sealed {}
32
33/// Trait for basic interaction with a [DisplayBuffer]
34#[allow(private_bounds)]
35pub trait Canvas: Sealed {
36    fn width(&self) -> u32;
37    fn height(&self) -> u32;
38    fn get_line_mut(&mut self, y: usize) -> &mut [u32];
39    fn get_line(&mut self, y: usize) -> &[u32];
40    fn set_pixel(&mut self, x: usize, y: usize, value: bool);
41    fn get_pixel(&self, x: usize, y: usize) -> bool;
42    fn fill(&mut self, value: bool);
43    fn buffer(&self) -> &[u32];
44
45    unsafe fn buffer_mut(&mut self) -> &mut [u32];
46}
47
48impl Sealed for DisplayBuffer<'_, OneField> {}
49impl Sealed for DisplayBuffer<'_, TwoFields> {}
50
51impl DisplayBuffer<'_, OneField> {
52    /// Points to the specified pixel by (buffer-index, bit-index)
53    ///
54    /// Should be used for low level access
55    fn pixel_index(&self, x: usize, y: usize) -> (usize, usize) {
56        (
57            self.buffer_pixel_offsets[0] + self.stride * y + x / 32,
58            x % 32,
59        )
60    }
61
62    /// The amount of words each display line uses in `buffer`
63    ///
64    /// Note: The last word of a line is never fully used (either partially or not at all)
65    const fn display_line_size(&self) -> usize {
66        // And no, this is not because of laziness regarding rounding,
67        // see comments in fn prepare_buffer
68        self.columns as usize / 32 + 1
69    }
70}
71
72impl Canvas for DisplayBuffer<'_, OneField> {
73    #[allow(missing_docs)]
74    fn width(&self) -> u32 {
75        self.columns
76    }
77
78    #[allow(missing_docs)]
79    fn height(&self) -> u32 {
80        self.lines
81    }
82
83    /// Gives you a mutable slice containing pixel data for a specific line
84    ///
85    /// Note: The last word of this slice is never fully used (either partially or not at all) and you can write anything you like there.
86    fn get_line_mut(&mut self, y: usize) -> &mut [u32] {
87        let start = self.buffer_pixel_offsets[0] + self.stride * y;
88        let display_line_size = self.display_line_size();
89        &mut self.buffer[start..start + display_line_size]
90    }
91
92    /// Gives you a slice containing pixel data for a specific line
93    ///
94    /// Note: The last word of this slice is never fully used (either partially or not at all)
95    fn get_line(&mut self, y: usize) -> &[u32] {
96        self.get_line_mut(y)
97    }
98
99    #[allow(missing_docs)]
100    fn set_pixel(&mut self, x: usize, y: usize, value: bool) {
101        let (word, bit) = self.pixel_index(x, y);
102        if value {
103            self.buffer[word] |= 1 << bit;
104        } else {
105            self.buffer[word] &= !(1 << bit);
106        }
107    }
108
109    #[allow(missing_docs)]
110    fn get_pixel(&self, x: usize, y: usize) -> bool {
111        let (word, bit) = self.pixel_index(x, y);
112        self.buffer[word] & (1 << bit) != 0
113    }
114
115    #[allow(missing_docs)]
116    fn fill(&mut self, value: bool) {
117        let fill_value = if value { u32::MAX } else { 0 };
118        let row_size = self.display_line_size();
119
120        for row in 0..self.lines as usize {
121            let row_offset = self.pixel_index(0, row).0;
122            let row_slice = &mut self.buffer[row_offset..row_offset + row_size];
123            row_slice.fill(fill_value);
124        }
125    }
126
127    /// Reference to the underlying buffer.
128    ///
129    /// For more info, see [DisplayBuffer::buffer_mut]
130    fn buffer(&self) -> &[u32] {
131        self.buffer
132    }
133
134    /// Mutable reference to the underlying buffer
135    ///
136    /// # Safety
137    ///
138    /// Be aware that there is more than just display data in the given slice.
139    /// If you change non-pixel data in this buffer, the PIO state-machine can (and probably will) start to behave wrong and hang.
140    /// It is advised to manipulate the `DisplayBuffer` with functions like [DisplayBuffer::get_line_mut]
141    unsafe fn buffer_mut(&mut self) -> &mut [u32] {
142        self.buffer
143    }
144}
145
146impl<'t> DisplayBuffer<'t, TwoFields> {
147    /// The amount of words each display line uses in `buffer`
148    ///
149    /// Note: The last word of a row is never fully used (either partially or not at all)
150    const fn display_line_size(&self) -> usize {
151        // And no, this is not because of laziness regarding rounding,
152        // see comments in fn prepare_buffer
153        self.columns as usize / 32 + 1
154    }
155
156    /// Points to the specified pixel by (buffer-index, bit-index)
157    ///
158    /// Should be used for low level access
159    fn pixel_index(&self, x: usize, y: usize) -> (usize, usize) // word index, bit index
160    {
161        let y2 = y / 2;
162
163        (
164            self.buffer_pixel_offsets[y & 1] + self.stride * y2 + x / 32,
165            x % 32,
166        )
167    }
168}
169
170impl Canvas for DisplayBuffer<'_, TwoFields> {
171    #[allow(missing_docs)]
172    fn width(&self) -> u32 {
173        self.columns
174    }
175
176    #[allow(missing_docs)]
177    fn height(&self) -> u32 {
178        self.lines
179    }
180
181    /// Gives you a mutable slice containing pixel data for a specific line
182    ///
183    /// Note: The last word of this slice is never fully used (either partially or not at all), and you can write anything you like there.
184    fn get_line_mut(&mut self, y: usize) -> &mut [u32] {
185        let y2 = y / 2;
186        let start = self.buffer_pixel_offsets[y & 1] + self.stride * y2;
187        let display_line_size = self.display_line_size();
188        &mut self.buffer[start..start + display_line_size]
189    }
190
191    /// Gives you a slice containing pixel data for a specific line
192    ///
193    /// Note: The last word of this slice is never fully used (either partially or not at all)
194    fn get_line(&mut self, y: usize) -> &[u32] {
195        self.get_line_mut(y)
196    }
197
198    #[allow(missing_docs)]
199    fn set_pixel(&mut self, x: usize, y: usize, value: bool) {
200        let (word, bit) = self.pixel_index(x, y);
201        if value {
202            self.buffer[word] |= 1 << bit;
203        } else {
204            self.buffer[word] &= !(1 << bit);
205        }
206    }
207
208    #[allow(missing_docs)]
209    fn get_pixel(&self, x: usize, y: usize) -> bool {
210        let (word, bit) = self.pixel_index(x, y);
211        self.buffer[word] & (1 << bit) != 0
212    }
213
214    #[allow(missing_docs)]
215    fn fill(&mut self, value: bool) {
216        let fill_value = if value { u32::MAX } else { 0 };
217        let row_size = self.display_line_size();
218
219        for row in 0..self.lines as usize {
220            let row_offset = self.pixel_index(0, row).0;
221            let row_slice = &mut self.buffer[row_offset..row_offset + row_size];
222            row_slice.fill(fill_value);
223        }
224    }
225
226    /// Reference to the underlying buffer.
227    ///
228    /// For more info, see [DisplayBuffer::buffer_mut]
229    fn buffer(&self) -> &[u32] {
230        self.buffer
231    }
232
233    /// Mutable reference to the underlying buffer
234    ///
235    /// # Safety
236    ///
237    /// Be aware that there is more than just display data in the given slice.
238    /// If you change non-pixel data in this buffer, the PIO state-machine can (and probably will) start to behave wrong and hang.
239    /// It is advised to manipulate the `DisplayBuffer` with functions like [DisplayBuffer::get_line_mut]
240    unsafe fn buffer_mut(&mut self) -> &mut [u32] {
241        self.buffer
242    }
243}
244
245pub trait NoFields: Copy {
246    const N: usize;
247}
248
249/// Marker indicating a [DisplayBuffer] has one field (e.g. in case of progressive video and semi-buffered interlaced)
250#[derive(Copy, Clone)]
251pub struct OneField;
252
253/// Marker indicating a [DisplayBuffer] has two fields (e.g. in case of interlaced video)
254#[derive(Copy, Clone)]
255pub struct TwoFields;
256
257impl NoFields for OneField {
258    const N: usize = 1;
259}
260
261impl NoFields for TwoFields {
262    const N: usize = 2;
263}