summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--CMakeLists.txt1
-rw-r--r--include/drm++/mode/mode.hpp138
-rw-r--r--src/mode/mode.cpp142
3 files changed, 281 insertions, 0 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index e12ed45..492bd1f 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -10,6 +10,7 @@ include(cmake/Diagnostics.cmake)
add_library(drm++ SHARED
"src/helper/ioctl.cpp"
"src/mode/framebuffer.cpp"
+ "src/mode/mode.cpp"
"src/drm.cpp"
"src/gem.cpp"
"src/syncobject.cpp")
diff --git a/include/drm++/mode/mode.hpp b/include/drm++/mode/mode.hpp
new file mode 100644
index 0000000..8df8845
--- /dev/null
+++ b/include/drm++/mode/mode.hpp
@@ -0,0 +1,138 @@
+/* SPDX-License-Identifier: MIT */
+
+#pragma once
+
+///
+/// * DRM Resource
+///
+/// ...
+///
+/// * Notes to self
+///
+/// - No encoder abstraction in atomic
+/// - No subpixel due to inconsistent
+/// - Might need to delete copy/move
+/// - Raw mode as drm_mode_modeinfo
+/// - Examine mode change behavior
+///
+
+#include "../helper/macros.hpp"
+#include "../helper/types.hpp"
+
+#include <string>
+#include <utility>
+#include <vector>
+
+namespace drm::mode {
+
+enum class ConnectorType : u32;
+
+///
+/// Mode information
+///
+struct ModeInfo {
+ /// Width and height in pixels
+ std::pair<u16, u16> resolution;
+ /// Refresh rate in Hz
+ double refreshRate;
+ /// Whether the mode is preferred (cannot be relied on)
+ bool preferred;
+
+ /// Raw drm_mode_modeinfo struct
+ u8 raw[68];
+};
+
+///
+/// CRTC object
+///
+struct Crtc {
+ u32 id;
+};
+
+///
+/// Connector object
+///
+struct Connector {
+ u32 id;
+
+ /// Type of the connector
+ ConnectorType type;
+ /// Index of the connector per type (e.g. DP-3 or HDMI-A-1)
+ u32 typeIndex;
+ /// Supported modes of the connector (may change after failed commit)
+ std::vector<ModeInfo> modes;
+ /// Physical size of the display in millimeters if available
+ std::pair<u32, u32> physicalSize;
+};
+
+struct Plane {
+ u32 id;
+
+ /// CRTC IDs the plane can be used with
+ std::vector<u32> crtcs;
+};
+
+///
+/// Modesetting resources
+///
+/// @throws drm::ioctl::Exception on failure
+///
+class Resources {
+public:
+ ///
+ /// Query all modesetting resources
+ ///
+ /// @param fetchModes Whether to fetch connector modes (blocking).
+ ///
+ Resources(int fd, bool fetchModes = false);
+
+ // Private access
+ GETTER(crtcs)
+ GETTER(connectors)
+ GETTER(planes)
+
+ // Default operators and destructor
+ DEFAULT_OPERATORS(Resources)
+ ~Resources() noexcept = default;
+private:
+ int m_fd;
+
+ std::vector<Crtc> m_crtcs;
+ std::vector<Connector> m_connectors;
+ std::vector<Plane> m_planes;
+};
+
+
+///
+/// Connector type
+///
+enum class ConnectorType : u32 {
+ Unknown = 0,
+ VGA = 1,
+ DVII = 2,
+ DVID = 3,
+ DVIA = 4,
+ Composite = 5,
+ SVIDEO = 6,
+ LVDS = 7,
+ Component = 8,
+ NPinDIN = 9,
+ DisplayPort = 10,
+ HDMI_A = 11,
+ HDMI_B = 12,
+ TV = 13,
+ eDP = 14,
+ Virtual = 15,
+ DSI = 16,
+ DPI = 17,
+ Writeback = 18,
+ SPI = 19,
+ USB = 20
+};
+
+///
+/// Convert a ConnectorType enum to a string representation
+///
+std::string connectorTypeToString(ConnectorType type);
+
+}
diff --git a/src/mode/mode.cpp b/src/mode/mode.cpp
new file mode 100644
index 0000000..1441b56
--- /dev/null
+++ b/src/mode/mode.cpp
@@ -0,0 +1,142 @@
+/* SPDX-License-Identifier: MIT */
+
+#include "drm++/mode/mode.hpp"
+#include "drm++/helper/ioctl.hpp"
+#include "drm++/helper/types.hpp"
+
+#include <cstring>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include <drm.h>
+#include <drm_mode.h>
+
+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<u32> crtc_ids(card_args.count_crtcs);
+ std::vector<u32> connector_ids(card_args.count_connectors);
+
+ card_args = {
+ .crtc_id_ptr = reinterpret_cast<u64>(crtc_ids.data()),
+ .connector_id_ptr = reinterpret_cast<u64>(connector_ids.data()),
+ .count_crtcs = static_cast<u32>(crtc_ids.size()),
+ .count_connectors = static_cast<u32>(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<u32>(crtc_id),
+ };
+ ioctl::perform(this->m_fd, DRM_IOCTL_MODE_GETCRTC, args);
+
+ this->m_crtcs.push_back({
+ .id = static_cast<u32>(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<u32>(connector_id),
+ };
+ ioctl::perform(this->m_fd, DRM_IOCTL_MODE_GETCONNECTOR, args);
+
+ std::vector<drm_mode_modeinfo> modes_raw(args.count_modes);
+ args = {
+ .modes_ptr = reinterpret_cast<u64>(modes_raw.data()),
+ .count_modes = static_cast<u32>(modes_raw.size()),
+ .connector_id = static_cast<u32>(connector_id),
+ };
+ ioctl::perform(this->m_fd, DRM_IOCTL_MODE_GETCONNECTOR, args);
+
+ std::vector<ModeInfo> 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<u32>(args.connector_id),
+ .type = static_cast<ConnectorType>(args.connector_type),
+ .typeIndex = static_cast<u32>(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<u32> plane_ids(plane_args.count_planes);
+
+ plane_args.plane_id_ptr = reinterpret_cast<u64>(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<u32>(plane_id),
+ };
+ ioctl::perform(this->m_fd, DRM_IOCTL_MODE_GETPLANE, args);
+
+ std::vector<u32> 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<u32>(args.plane_id),
+ .crtcs = std::vector<u32>(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";
+ }
+}