Skip to main content

breakwater_core/
framebuffer.rs

1use std::slice;
2
3pub struct FrameBuffer {
4    width: usize,
5    height: usize,
6    buffer: Vec<u32>,
7}
8
9impl FrameBuffer {
10    pub fn new(width: usize, height: usize) -> Self {
11        let mut buffer = Vec::with_capacity(width * height);
12        buffer.resize_with(width * height, || 0);
13        FrameBuffer {
14            width,
15            height,
16            buffer,
17        }
18    }
19
20    pub fn get_width(&self) -> usize {
21        self.width
22    }
23
24    pub fn get_height(&self) -> usize {
25        self.height
26    }
27
28    pub fn get_size(&self) -> usize {
29        self.width * self.height
30    }
31
32    #[inline(always)]
33    pub fn get(&self, x: usize, y: usize) -> Option<u32> {
34        if x < self.width && y < self.height {
35            Some(*unsafe { self.buffer.get_unchecked(x + y * self.width) })
36        } else {
37            None
38        }
39    }
40
41    #[inline(always)]
42    pub fn get_unchecked(&self, x: usize, y: usize) -> u32 {
43        *unsafe { self.buffer.get_unchecked(x + y * self.width) }
44    }
45
46    #[inline(always)]
47    pub fn set(&self, x: usize, y: usize, rgba: u32) {
48        // https://github.com/sbernauer/breakwater/pull/11
49        // If we make the FrameBuffer large enough (e.g. 10_000 x 10_000) we don't need to check the bounds here
50        // (x and y are max 4 digit numbers). Flamegraph has shown 5.21% of runtime in this bound check. On the other
51        // hand this can increase the framebuffer size dramatically and lowers the cash locality.
52        // In the end we did *not* go with this change.
53        if x < self.width && y < self.height {
54            unsafe {
55                let ptr = self.buffer.as_ptr().add(x + y * self.width) as *mut u32;
56                *ptr = rgba;
57            }
58        }
59    }
60
61    pub fn get_buffer(&self) -> &[u32] {
62        &self.buffer
63    }
64
65    pub fn as_bytes(&self) -> &[u8] {
66        let len_in_bytes = self.buffer.len() * 4;
67        unsafe { slice::from_raw_parts(self.buffer.as_ptr() as *const u8, len_in_bytes) }
68    }
69}