Connector: improve get_mode(string)
[android/external-libkmsxx.git] / kms++ / src / connector.cpp
1 #include <stdio.h>
2 #include <iostream>
3 #include <unistd.h>
4 #include <fcntl.h>
5 #include <cassert>
6 #include <cmath>
8 #include <kms++/kms++.h>
9 #include "helpers.h"
11 using namespace std;
13 namespace kms
14 {
16 #ifndef DRM_MODE_CONNECTOR_DPI
17 #define DRM_MODE_CONNECTOR_DPI 17
18 #endif
20 static const map<int, string> connector_names = {
21         { DRM_MODE_CONNECTOR_Unknown, "Unknown" },
22         { DRM_MODE_CONNECTOR_VGA, "VGA" },
23         { DRM_MODE_CONNECTOR_DVII, "DVI-I" },
24         { DRM_MODE_CONNECTOR_DVID, "DVI-D" },
25         { DRM_MODE_CONNECTOR_DVIA, "DVI-A" },
26         { DRM_MODE_CONNECTOR_Composite, "Composite" },
27         { DRM_MODE_CONNECTOR_SVIDEO, "S-Video" },
28         { DRM_MODE_CONNECTOR_LVDS, "LVDS" },
29         { DRM_MODE_CONNECTOR_Component, "Component" },
30         { DRM_MODE_CONNECTOR_9PinDIN, "9-Pin-DIN" },
31         { DRM_MODE_CONNECTOR_DisplayPort, "DP" },
32         { DRM_MODE_CONNECTOR_HDMIA, "HDMI-A" },
33         { DRM_MODE_CONNECTOR_HDMIB, "HDMI-B" },
34         { DRM_MODE_CONNECTOR_TV, "TV" },
35         { DRM_MODE_CONNECTOR_eDP, "eDP" },
36         { DRM_MODE_CONNECTOR_VIRTUAL, "Virtual" },
37         { DRM_MODE_CONNECTOR_DSI, "DSI" },
38         { DRM_MODE_CONNECTOR_DPI, "DPI" },
39 };
41 static const map<int, string> connection_str = {
42         { 0, "<unknown>" },
43         { DRM_MODE_CONNECTED, "Connected" },
44         { DRM_MODE_DISCONNECTED, "Disconnected" },
45         { DRM_MODE_UNKNOWNCONNECTION, "Unknown" },
46 };
48 static const map<int, string> subpix_str = {
49 #define DEF_SUBPIX(c) { DRM_MODE_SUBPIXEL_##c, #c }
50         DEF_SUBPIX(UNKNOWN),
51         DEF_SUBPIX(HORIZONTAL_RGB),
52         DEF_SUBPIX(HORIZONTAL_BGR),
53         DEF_SUBPIX(VERTICAL_RGB),
54         DEF_SUBPIX(VERTICAL_BGR),
55         DEF_SUBPIX(NONE),
56 #undef DEF_SUBPIX
57 };
59 struct ConnectorPriv
60 {
61         drmModeConnectorPtr drm_connector;
62 };
64 Connector::Connector(Card &card, uint32_t id, uint32_t idx)
65         :DrmPropObject(card, id, DRM_MODE_OBJECT_CONNECTOR, idx)
66 {
67         m_priv = new ConnectorPriv();
69         m_priv->drm_connector = drmModeGetConnector(this->card().fd(), this->id());
70         assert(m_priv->drm_connector);
72         // XXX drmModeGetConnector() does forced probe, which seems to change (at least) EDID blob id.
73         // XXX So refresh the props again here.
74         refresh_props();
76         const auto& name = connector_names.at(m_priv->drm_connector->connector_type);
77         m_fullname = name + "-" + to_string(m_priv->drm_connector->connector_type_id);
78 }
80 Connector::~Connector()
81 {
82         drmModeFreeConnector(m_priv->drm_connector);
83         delete m_priv;
84 }
86 void Connector::refresh()
87 {
88         drmModeFreeConnector(m_priv->drm_connector);
90         m_priv->drm_connector = drmModeGetConnector(this->card().fd(), this->id());
91         assert(m_priv->drm_connector);
93         // XXX drmModeGetConnector() does forced probe, which seems to change (at least) EDID blob id.
94         // XXX So refresh the props again here.
95         refresh_props();
97         const auto& name = connector_names.at(m_priv->drm_connector->connector_type);
98         m_fullname = name + "-" + to_string(m_priv->drm_connector->connector_type_id);
99 }
101 void Connector::setup()
103         if (m_priv->drm_connector->encoder_id != 0)
104                 m_current_encoder = card().get_encoder(m_priv->drm_connector->encoder_id);
105         else
106                 m_current_encoder = 0;
108         if (m_current_encoder)
109                 m_saved_crtc = m_current_encoder->get_crtc();
110         else
111                 m_saved_crtc = 0;
114 void Connector::restore_mode()
116         if (m_saved_crtc)
117                 m_saved_crtc->restore_mode(this);
120 Videomode Connector::get_default_mode() const
122         if (m_priv->drm_connector->count_modes == 0)
123                 throw invalid_argument("no modes available\n");
124         drmModeModeInfo drmmode = m_priv->drm_connector->modes[0];
126         return drm_mode_to_video_mode(drmmode);
129 Videomode Connector::get_mode(const string& mode) const
131         auto c = m_priv->drm_connector;
133         size_t idx = mode.find('@');
135         string name = idx == string::npos ? mode : mode.substr(0, idx);
136         float vrefresh = idx == string::npos ? 0.0 : stod(mode.substr(idx + 1));
138         for (int i = 0; i < c->count_modes; i++) {
139                 Videomode m = drm_mode_to_video_mode(c->modes[i]);
141                 if (m.name != name)
142                         continue;
144                 if (vrefresh && vrefresh != m.calculated_vrefresh())
145                         continue;
147                 return m;
148         }
150         throw invalid_argument(mode + ": mode not found");
153 Videomode Connector::get_mode(unsigned xres, unsigned yres, float vrefresh, bool ilace) const
155         auto c = m_priv->drm_connector;
157         for (int i = 0; i < c->count_modes; i++) {
158                 Videomode m = drm_mode_to_video_mode(c->modes[i]);
160                 if (m.hdisplay != xres || m.vdisplay != yres)
161                         continue;
163                 if (ilace != m.interlace())
164                         continue;
166                 if (vrefresh && vrefresh != m.calculated_vrefresh())
167                         continue;
169                 return m;
170         }
172         // If not found, do another round using rounded vrefresh
174         for (int i = 0; i < c->count_modes; i++) {
175                 Videomode m = drm_mode_to_video_mode(c->modes[i]);
177                 if (m.hdisplay != xres || m.vdisplay != yres)
178                         continue;
180                 if (ilace != m.interlace())
181                         continue;
183                 if (vrefresh && vrefresh != roundf(m.calculated_vrefresh()))
184                         continue;
186                 return m;
187         }
189         throw invalid_argument("mode not found");
192 bool Connector::connected() const
194         return m_priv->drm_connector->connection == DRM_MODE_CONNECTED ||
195                         m_priv->drm_connector->connection == DRM_MODE_UNKNOWNCONNECTION;
198 vector<Crtc*> Connector::get_possible_crtcs() const
200         vector<Crtc*> crtcs;
202         for (int i = 0; i < m_priv->drm_connector->count_encoders; ++i) {
203                 auto enc = card().get_encoder(m_priv->drm_connector->encoders[i]);
205                 auto l = enc->get_possible_crtcs();
207                 crtcs.insert(crtcs.end(), l.begin(), l.end());
208         }
210         return crtcs;
213 Crtc* Connector::get_current_crtc() const
215         if (m_current_encoder)
216                 return m_current_encoder->get_crtc();
217         else
218                 return 0;
221 uint32_t Connector::connector_type() const
223         return m_priv->drm_connector->connector_type;
226 uint32_t Connector::connector_type_id() const
228         return m_priv->drm_connector->connector_type_id;
231 uint32_t Connector::mmWidth() const
233         return m_priv->drm_connector->mmWidth;
236 uint32_t Connector::mmHeight() const
238         return m_priv->drm_connector->mmHeight;
241 uint32_t Connector::subpixel() const
243         return m_priv->drm_connector->subpixel;
246 const string& Connector::subpixel_str() const
248         return subpix_str.at(subpixel());
251 std::vector<Videomode> Connector::get_modes() const
253         vector<Videomode> modes;
255         for (int i = 0; i < m_priv->drm_connector->count_modes; i++)
256                 modes.push_back(drm_mode_to_video_mode(
257                                         m_priv->drm_connector->modes[i]));
259         return modes;
262 std::vector<Encoder*> Connector::get_encoders() const
264         vector<Encoder*> encoders;
266         for (int i = 0; i < m_priv->drm_connector->count_encoders; i++) {
267                 auto enc = card().get_encoder(m_priv->drm_connector->encoders[i]);
268                 encoders.push_back(enc);
269         }
270         return encoders;