/* SPDX-License-Identifier: MIT */ #include "drm++/mode/mode.hpp" #include "drm++/helper/ioctl.hpp" #include "drm++/helper/types.hpp" #include #include #include #include #include #include using namespace drm; using namespace drm::mode; Resources::Resources(int fd, bool fetchModes) : m_fd(fd) { drm_mode_card_res card_args{ .count_crtcs = 0, }; ioctl::perform(this->m_fd, DRM_IOCTL_MODE_GETRESOURCES, card_args); std::vector crtc_ids(card_args.count_crtcs); std::vector connector_ids(card_args.count_connectors); card_args = { .crtc_id_ptr = reinterpret_cast(crtc_ids.data()), .connector_id_ptr = reinterpret_cast(connector_ids.data()), .count_crtcs = static_cast(crtc_ids.size()), .count_connectors = static_cast(connector_ids.size()) }; ioctl::perform(this->m_fd, DRM_IOCTL_MODE_GETRESOURCES, card_args); this->m_crtcs.reserve(card_args.count_crtcs); for (const u32 crtc_id : crtc_ids) { drm_mode_crtc args{ .crtc_id = static_cast(crtc_id), }; ioctl::perform(this->m_fd, DRM_IOCTL_MODE_GETCRTC, args); this->m_crtcs.push_back({ .id = static_cast(args.crtc_id), }); } this->m_connectors.reserve(card_args.count_connectors); for (const u32 connector_id : connector_ids) { drm_mode_get_connector args{ .count_modes = fetchModes ? 0U : 1U, .connector_id = static_cast(connector_id), }; ioctl::perform(this->m_fd, DRM_IOCTL_MODE_GETCONNECTOR, args); std::vector modes_raw(args.count_modes); args = { .modes_ptr = reinterpret_cast(modes_raw.data()), .count_modes = static_cast(modes_raw.size()), .connector_id = static_cast(connector_id), }; ioctl::perform(this->m_fd, DRM_IOCTL_MODE_GETCONNECTOR, args); std::vector modes; modes.reserve(modes_raw.size()); for (const auto& mode_raw : modes_raw) { modes.push_back({ .resolution = { mode_raw.hdisplay, mode_raw.vdisplay }, .refreshRate = (mode_raw.clock * 1000.0) / (mode_raw.htotal * mode_raw.vtotal), .preferred = (mode_raw.type & DRM_MODE_TYPE_PREFERRED) != 0, .raw = {0}, }); std::memcpy(modes.back().raw, &mode_raw, sizeof(mode_raw)); // NOLINT (raw memory) } this->m_connectors.push_back({ .id = static_cast(args.connector_id), .type = static_cast(args.connector_type), .typeIndex = static_cast(args.connector_type_id), .modes = std::move(modes), .physicalSize = { args.mm_width, args.mm_height }, }); } // Fetch planes drm_mode_get_plane_res plane_args{ .count_planes = 0, }; ioctl::perform(this->m_fd, DRM_IOCTL_MODE_GETPLANERESOURCES, plane_args); std::vector plane_ids(plane_args.count_planes); plane_args.plane_id_ptr = reinterpret_cast(plane_ids.data()); ioctl::perform(this->m_fd, DRM_IOCTL_MODE_GETPLANERESOURCES, plane_args); this->m_planes.reserve(plane_args.count_planes); for (const u32 plane_id : plane_ids) { drm_mode_get_plane args{ .plane_id = static_cast(plane_id), }; ioctl::perform(this->m_fd, DRM_IOCTL_MODE_GETPLANE, args); std::vector possible_crtcs; for (u32 i = 0; i < this->m_crtcs.size(); ++i) { if (!(args.possible_crtcs & (1 << i))) continue; possible_crtcs.push_back(this->m_crtcs.at(i).id); } this->m_planes.push_back({ .id = static_cast(args.plane_id), .crtcs = std::vector(possible_crtcs), }); } } /* Enums */ std::string mode::connectorTypeToString(ConnectorType type) { switch (type) { case ConnectorType::Unknown: return "Unknown"; case ConnectorType::VGA: return "VGA"; case ConnectorType::DVII: return "DVI-I"; case ConnectorType::DVID: return "DVI-D"; case ConnectorType::DVIA: return "DVI-A"; case ConnectorType::Composite: return "Composite"; case ConnectorType::SVIDEO: return "SVIDEO"; case ConnectorType::LVDS: return "LVDS"; case ConnectorType::Component: return "Component"; case ConnectorType::NPinDIN: return "DIN"; case ConnectorType::DisplayPort: return "DP"; case ConnectorType::HDMI_A: return "HDMI-A"; case ConnectorType::HDMI_B: return "HDMI-B"; case ConnectorType::TV: return "TV"; case ConnectorType::eDP: return "eDP"; case ConnectorType::Virtual: return "Virtual"; case ConnectorType::DSI: return "DSI"; case ConnectorType::DPI: return "DPI"; case ConnectorType::Writeback: return "Writeback"; case ConnectorType::SPI: return "SPI"; case ConnectorType::USB: return "USB"; } }