1 #include <xf86drm.h>
2 #include <xf86drmMode.h>
3 #include <cmath>
4 #include <sstream>
5 #include <fmt/format.h>
6
7 #include <kms++/kms++.h>
8 #include "helpers.h"
9
10 using namespace std;
11
12 namespace kms
13 {
valid() const14 bool Videomode::valid() const
15 {
16 return !!clock;
17 }
18
to_blob(Card & card) const19 unique_ptr<Blob> Videomode::to_blob(Card& card) const
20 {
21 drmModeModeInfo drm_mode = video_mode_to_drm_mode(*this);
22
23 return unique_ptr<Blob>(new Blob(card, &drm_mode, sizeof(drm_mode)));
24 }
25
calculated_vrefresh() const26 float Videomode::calculated_vrefresh() const
27 {
28 // XXX interlace should only halve visible vertical lines, not blanking
29 float refresh = (clock * 1000.0) / (htotal * vtotal) * (interlace() ? 2 : 1);
30 return roundf(refresh * 100.0) / 100.0;
31 }
32
interlace() const33 bool Videomode::interlace() const
34 {
35 return flags & DRM_MODE_FLAG_INTERLACE;
36 }
37
hsync() const38 SyncPolarity Videomode::hsync() const
39 {
40 if (flags & DRM_MODE_FLAG_PHSYNC)
41 return SyncPolarity::Positive;
42 if (flags & DRM_MODE_FLAG_NHSYNC)
43 return SyncPolarity::Negative;
44 return SyncPolarity::Undefined;
45 }
46
vsync() const47 SyncPolarity Videomode::vsync() const
48 {
49 if (flags & DRM_MODE_FLAG_PVSYNC)
50 return SyncPolarity::Positive;
51 if (flags & DRM_MODE_FLAG_NVSYNC)
52 return SyncPolarity::Negative;
53 return SyncPolarity::Undefined;
54 }
55
set_interlace(bool ilace)56 void Videomode::set_interlace(bool ilace)
57 {
58 if (ilace)
59 flags |= DRM_MODE_FLAG_INTERLACE;
60 else
61 flags &= ~DRM_MODE_FLAG_INTERLACE;
62 }
63
set_hsync(SyncPolarity pol)64 void Videomode::set_hsync(SyncPolarity pol)
65 {
66 flags &= ~(DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NHSYNC);
67
68 switch (pol) {
69 case SyncPolarity::Positive:
70 flags |= DRM_MODE_FLAG_PHSYNC;
71 break;
72 case SyncPolarity::Negative:
73 flags |= DRM_MODE_FLAG_NHSYNC;
74 break;
75 default:
76 break;
77 }
78 }
79
set_vsync(SyncPolarity pol)80 void Videomode::set_vsync(SyncPolarity pol)
81 {
82 flags &= ~(DRM_MODE_FLAG_PVSYNC | DRM_MODE_FLAG_NVSYNC);
83
84 switch (pol) {
85 case SyncPolarity::Positive:
86 flags |= DRM_MODE_FLAG_PVSYNC;
87 break;
88 case SyncPolarity::Negative:
89 flags |= DRM_MODE_FLAG_NVSYNC;
90 break;
91 default:
92 break;
93 }
94 }
95
to_string_short() const96 string Videomode::to_string_short() const
97 {
98 return fmt::format("{}x{}{}@{:.2f}", hdisplay, vdisplay, interlace() ? "i" : "", calculated_vrefresh());
99 }
100
sync_to_char(SyncPolarity pol)101 static char sync_to_char(SyncPolarity pol)
102 {
103 switch (pol) {
104 case SyncPolarity::Positive:
105 return '+';
106 case SyncPolarity::Negative:
107 return '-';
108 default:
109 return '?';
110 }
111 }
112
to_string_long() const113 string Videomode::to_string_long() const
114 {
115 string h = fmt::format("{}/{}/{}/{}/{}", hdisplay, hfp(), hsw(), hbp(), sync_to_char(hsync()));
116 string v = fmt::format("{}/{}/{}/{}/{}", vdisplay, vfp(), vsw(), vbp(), sync_to_char(vsync()));
117
118 string str = fmt::format("{} {:.3f} {} {} {} ({:.2f}) {:#x} {:#x}",
119 to_string_short(),
120 clock / 1000.0,
121 h, v,
122 vrefresh, calculated_vrefresh(),
123 flags,
124 type);
125
126 return str;
127 }
128
to_string_long_padded() const129 string Videomode::to_string_long_padded() const
130 {
131 string h = fmt::format("{}/{}/{}/{}/{}", hdisplay, hfp(), hsw(), hbp(), sync_to_char(hsync()));
132 string v = fmt::format("{}/{}/{}/{}/{}", vdisplay, vfp(), vsw(), vbp(), sync_to_char(vsync()));
133
134 string str = fmt::format("{:<16} {:7.3f} {:<18} {:<18} {:2} ({:.2f}) {:#10x} {:#6x}",
135 to_string_short(),
136 clock / 1000.0,
137 h, v,
138 vrefresh, calculated_vrefresh(),
139 flags,
140 type);
141
142 return str;
143 }
144
videomode_from_timings(uint32_t clock_khz,uint16_t hact,uint16_t hfp,uint16_t hsw,uint16_t hbp,uint16_t vact,uint16_t vfp,uint16_t vsw,uint16_t vbp)145 Videomode videomode_from_timings(uint32_t clock_khz,
146 uint16_t hact, uint16_t hfp, uint16_t hsw, uint16_t hbp,
147 uint16_t vact, uint16_t vfp, uint16_t vsw, uint16_t vbp)
148 {
149 Videomode m{};
150 m.clock = clock_khz;
151
152 m.hdisplay = hact;
153 m.hsync_start = hact + hfp;
154 m.hsync_end = hact + hfp + hsw;
155 m.htotal = hact + hfp + hsw + hbp;
156
157 m.vdisplay = vact;
158 m.vsync_start = vact + vfp;
159 m.vsync_end = vact + vfp + vsw;
160 m.vtotal = vact + vfp + vsw + vbp;
161
162 return m;
163 }
164
165 } // namespace kms
166