1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
use std::{ffi::OsString, os::fd::{AsRawFd, OwnedFd}};
use crate::uapi::i915::DrmGemHandle;

use super::super::uapi;
use std::path::Path;
use std::fs::File;

pub use uapi::i915::GemIoctlError;

#[derive(Debug)]
pub struct DrmDeviceNode {
    pub fd: OwnedFd,
    pub path: Option<OsString>,
}

#[derive(Debug)]
pub struct GemHandle<'a> {
    pub handle: DrmGemHandle,
    pub node: &'a DrmDeviceNode,
}

/// An owned GEM handle that will be closed when dropped
impl GemHandle<'_> {
    pub fn new(node: &DrmDeviceNode, size: u64) -> Option<GemHandle> {
        uapi::i915::make_gem(node.fd.as_raw_fd(), size).map(|handle| GemHandle {
            handle: handle,
            node: &node,
        })
    }

    pub fn from_handle(node: &DrmDeviceNode, handle: DrmGemHandle) -> Result<GemHandle, GemIoctlError> {
        // Avoid invoking GemHandle::is_valid() here to prevent the drop() method from trying to drop an invalid handle
        let is_valid = uapi::i915::gem_is_valid(node.fd.as_raw_fd(), handle);

        if is_valid.is_ok() && is_valid.unwrap() {
            let res = GemHandle {
                handle: handle,
                node: &node,
            };
            return Ok(res);
        } else {
            return Err(is_valid.err().unwrap_or(GemIoctlError::PermissionDenied));
        }
    }

    pub fn close(&mut self) -> Result<(), i32> {
        return uapi::i915::close_gem(self.node.fd.as_raw_fd(), self.handle);
    }

    pub fn has_tiling(&self) -> Result<bool, uapi::i915::GemIoctlError> {
        uapi::i915::gem_has_tiling(self.node.fd.as_raw_fd(), self.handle)
    }

    pub fn is_valid(&self) -> Result<bool, GemIoctlError> {
        uapi::i915::gem_is_valid(self.node.fd.as_raw_fd(), self.handle)
    }
}

impl Drop for GemHandle<'_> {
    fn drop(&mut self) {
        // Ignoring the close failing as an invalid Gem handle's drop is a no-op
        let _ = self.close();
    }
}

#[derive(Debug)]
pub struct Device {
    pub node: DrmDeviceNode,
    pub driver: uapi::DrmVersion,
}

#[derive(Debug)]
pub struct Engine {
    pub info: uapi::i915::EngineInfo,
}

pub fn find_device() -> Option<Device> {
    uapi::i915::find_node().and_then(|file| Device::from_path(file.path?))
}

impl Device {
    pub fn from_fd(fd: OwnedFd) -> Option<Device> {
        let driver = uapi::get_drm_version(fd.as_raw_fd())?;
        Some(Device {
            node: DrmDeviceNode {
                fd: fd,
                path: None,
            },
            driver: driver,
        })
    }
    pub fn from_path(path: OsString) -> Option<Device> {
        let file = File::open(Path::new(&path)).ok()?;
        let driver = uapi::get_drm_version(file.as_raw_fd())?;
        Some(Device {
            node: DrmDeviceNode {
                fd: OwnedFd::from(file),
                path: Some(path),
            },
            driver: driver,
        })
    }
    pub fn get_engines(&self) -> Option<Vec<Engine>> {
        uapi::i915::get_engines(self.node.fd.as_raw_fd()).map(|engines| {
            engines.into_iter().map(|engine_info| {
                Engine {
                    info: engine_info,
                }
            }).collect()
        })
    }
    pub fn get_param(&self, param: u32) -> Option<i32> {
        uapi::i915::get_param(self.node.fd.as_raw_fd(), param as i32)
    }
}