Skip to main content

drm_gfx/
drm_render_target.rs

1// #![allow(dead_code)]
2use drm::control::{Device as ControlDevice, dumbbuffer::DumbBuffer, framebuffer};
3// use drm::{buffer, Device};
4use crate::card::Card;
5use drm::buffer::{Buffer, DrmFourcc};
6use drm::control::{Mode, connector, crtc};
7use log::{debug, error, trace};
8
9pub struct RenderTarget {
10    pub card: Card,
11    pub crtc: crtc::Handle,
12    pub connection: connector::Handle,
13    pub fb: framebuffer::Handle,
14    pub db: DumbBuffer,
15    pub width: usize,
16    pub height: usize,
17    pub format: DrmFourcc,
18    pub mode: Mode,
19}
20
21impl Default for RenderTarget {
22    fn default() -> Self {
23        let device_paths = [
24            "/dev/dri/card0",
25            "/dev/dri/card1",
26            "/dev/dri/card2",
27            "/dev/dri/renderD128",
28            "/dev/dri/renderD129",
29        ];
30        for dev in device_paths {
31            match Self::new(dev) {
32                Ok(render_target) => {
33                    trace!("Created render target for device {dev}");
34                    return render_target;
35                }
36                Err(e) => {
37                    trace!("Could not created render target for device {dev}: {e}");
38                    continue;
39                }
40            }
41        }
42
43        error!("Could not create any render target!");
44        panic!("Could not create any render target!");
45    }
46}
47
48impl RenderTarget {
49    pub fn new(device: &str) -> Result<Self, std::io::Error> {
50        let card = Card::open_global(device)
51            .inspect_err(|e| error!("failed to open device {device}: {e}"))?;
52
53        // Load the information.
54        let res = card
55            .resource_handles()
56            .inspect_err(|e| error!("failed to load resource handle ids from {device}: {e}"))?;
57
58        let coninfo: Vec<connector::Info> = res
59            .connectors()
60            .iter()
61            .flat_map(|con| card.get_connector(*con, true))
62            .collect();
63        let crtcinfo: Vec<crtc::Info> = res
64            .crtcs()
65            .iter()
66            .flat_map(|crtc| card.get_crtc(*crtc))
67            .collect();
68
69        // Filter each connector until we find one that's connected.
70        let con = coninfo
71            .iter()
72            .find(|&i| i.state() == connector::State::Connected)
73            .expect("No connected connectors");
74
75        // Get the first (usually best) mode
76        let &mode = con.modes().first().expect("No modes found on connector");
77
78        let (width, height) = mode.size();
79
80        // Find a crtc and FB
81        let crtc = crtcinfo.first().expect("No crtcs found");
82
83        // Select the pixel format
84        let format = DrmFourcc::Xrgb8888;
85
86        // Create a DB
87        // If buffer resolution is larger than display resolution, an ENOSPC (not enough video memory)
88        // error may occur
89        let mut db = card
90            .create_dumb_buffer((width.into(), height.into()), format, 32)
91            .expect("Could not create dumb buffer");
92
93        // Map it and grey it out.
94        {
95            let mut map = card
96                .map_dumb_buffer(&mut db)
97                .expect("Could not map dumbbuffer");
98            // for b in map.as_mut() {
99            //     *b = 128;
100            // }
101            let buf = map.as_mut();
102            let line_length = width as u64 * 4;
103            for j in 0..height {
104                if j % 2 == 0 {
105                    continue;
106                }
107                let line_offset = j as u64 * line_length;
108                for i in 0..width {
109                    if i % 2 == 0 {
110                        continue;
111                    }
112                    let offset = (line_offset + i as u64 * 4) as usize;
113                    if offset + 4 > buf.len() {
114                        panic!("Buffer overflow at offset {offset}");
115                    }
116                    buf[offset] = 128; // B
117                    buf[offset + 1] = 0; // G
118                    buf[offset + 2] = 128; // R
119                    buf[offset + 3] = 255; // A
120                }
121            }
122        }
123
124        // Create an FB:
125        let fb = card
126            .add_framebuffer(&db, 24, 32)
127            .expect("Could not create FB");
128
129        debug!("mode: {mode:#?}");
130        trace!("frame buffer handle:{fb:#?}");
131        trace!("dumb buffer{db:#?}");
132
133        // Set the crtc
134        // On many setups, this requires root access.
135        card.set_crtc(crtc.handle(), Some(fb), (0, 0), &[con.handle()], Some(mode))
136            .expect("Could not set CRTC");
137
138        Ok(Self {
139            card,
140            crtc: crtc.handle(),
141            connection: con.handle(),
142            fb,
143            db,
144            width: width as usize,
145            height: height as usize,
146            format,
147            mode,
148        })
149    }
150
151    pub fn destroy(&self) {
152        trace!("Destroy the framebuffer");
153        self.card.destroy_framebuffer(self.fb).unwrap();
154        self.card.destroy_dumb_buffer(self.db).unwrap();
155    }
156
157    pub fn get_info(&self) -> String {
158        format!(
159            "RenderTarget details:  mode: {:#?} -- buffer: {:#?}",
160            self.mode, self.db,
161        )
162    }
163}
164
165#[derive(Debug)]
166pub enum FbWriteError {
167    Error,
168}
169pub trait FramebufferTarget {
170    fn eat_framebuffer(&mut self, buf: &[u32]) -> Result<(), FbWriteError>;
171}
172impl FramebufferTarget for RenderTarget {
173    fn eat_framebuffer(&mut self, buffer: &[u32]) -> Result<(), FbWriteError> {
174        let pixel_count = self.db.size().0 as usize * self.db.size().1 as usize;
175        if buffer.len() != pixel_count {
176            panic!(
177                "Buffer length mismatch: expected {}, got {}",
178                pixel_count,
179                buffer.len()
180            );
181        }
182        // Map it and cycle colors.
183        {
184            let mut map = self
185                .card
186                .map_dumb_buffer(&mut self.db)
187                .expect("Could not map dumbbuffer");
188            let buf = map.as_mut();
189            let buf_line_length = self.width as u64 * 4;
190            let buffer_line_length = self.width as u64;
191            for j in 0..self.height {
192                let buf_line_offset = j as u64 * buf_line_length;
193                let buffer_line_offset = j as u64 * buffer_line_length;
194                for i in 0..self.width {
195                    let buf_offset = (buf_line_offset + i as u64 * 4) as usize;
196                    let buffer_offset = (buffer_line_offset + i as u64) as usize;
197                    // if buf_offset + 4 > buf.len() {
198                    //     panic!("Buf overflow at offset {}", buf_offset);
199                    // }
200                    // if buffer_offset > buffer.len() {
201                    //     panic!("Buffer overflow at offset {}", buffer_offset);
202                    // }
203
204                    buf[buf_offset] = ((buffer[buffer_offset] >> 24) & 0xff) as u8; // B
205                    buf[buf_offset + 1] = ((buffer[buffer_offset] >> 16) & 0xff) as u8; // G
206                    buf[buf_offset + 2] = ((buffer[buffer_offset] >> 8) & 0xff) as u8; // R
207                    buf[buf_offset + 3] = 255; // A
208                }
209            }
210        }
211        // Create an FB:
212        let fb = self
213            .card
214            .add_framebuffer(&self.db, 24, 32)
215            .expect("Could not create FB");
216        self.card
217            .set_crtc(
218                self.crtc,
219                Some(fb),
220                (0, 0),
221                &[self.connection],
222                Some(self.mode),
223            )
224            .expect("Could not set CRTC");
225
226        Ok(())
227    }
228}