modedb_dmt: update table
[android/external-libkmsxx.git] / utils / kmsprint.cpp
1 #include <algorithm>
2 #include <cinttypes>
3 #include <cstdio>
4 #include <iostream>
5 #include <string>
6 #include <unistd.h>
8 #include <kms++/kms++.h>
9 #include <kms++util/kms++util.h>
11 using namespace std;
12 using namespace kms;
14 static struct {
15         bool print_props;
16         bool print_modes;
17         bool print_list;
18         bool x_modeline;
19 } s_opts;
21 static string format_mode(const Videomode& m, unsigned idx)
22 {
23         string str;
25         str = sformat("  %2u ", idx);
27         if (s_opts.x_modeline) {
28                 str += sformat("%12s %6u %4u %4u %4u %4u %4u %4u %4u %4u  %2u %#x %#x",
29                                m.name.c_str(),
30                                m.clock,
31                                m.hdisplay, m.hsync_start, m.hsync_end, m.htotal,
32                                m.vdisplay, m.vsync_start, m.vsync_end, m.vtotal,
33                                m.vrefresh,
34                                m.flags,
35                                m.type);
36         } else {
37                 string h = sformat("%u/%u/%u/%u", m.hdisplay, m.hfp(), m.hsw(), m.hbp());
38                 string v = sformat("%u/%u/%u/%u", m.vdisplay, m.vfp(), m.vsw(), m.vbp());
40                 str += sformat("%-12s %7.3f %-16s %-16s %2u (%.2f) %#10x %#6x",
41                                m.name.c_str(),
42                                m.clock / 1000.0,
43                                h.c_str(), v.c_str(),
44                                m.vrefresh, m.calculated_vrefresh(),
45                                m.flags,
46                                m.type);
47         }
49         return str;
50 }
52 static string format_mode_short(const Videomode& m)
53 {
54         string h = sformat("%u/%u/%u/%u", m.hdisplay, m.hfp(), m.hsw(), m.hbp());
55         string v = sformat("%u/%u/%u/%u", m.vdisplay, m.vfp(), m.vsw(), m.vbp());
57         return sformat("%s %.3f %s %s %u (%.2f)",
58                        m.name.c_str(),
59                        m.clock / 1000.0,
60                        h.c_str(), v.c_str(),
61                        m.vrefresh, m.calculated_vrefresh());
62 }
64 static string format_connector(Connector& c)
65 {
66         string str;
68         str = sformat("Connector %u (%u) %s",
69                       c.idx(), c.id(), c.fullname().c_str());
71         if (c.connected())
72                 str += " (connected)";
74         return str;
75 }
77 static string format_encoder(Encoder& e)
78 {
79         return sformat("Encoder %u (%u) %s",
80                        e.idx(), e.id(), e.get_encoder_type().c_str());
81 }
83 static string format_crtc(Crtc& c)
84 {
85         string str;
87         str = sformat("Crtc %u (%u)", c.idx(), c.id());
89         if (c.mode_valid())
90                 str += " " + format_mode_short(c.mode());
92         return str;
93 }
95 static string format_plane(Plane& p)
96 {
97         string str;
99         str = sformat("Plane %u (%u)", p.idx(), p.id());
101         if (p.fb_id())
102                 str += sformat(" fb-id: %u", p.fb_id());
104         if (p.card().has_atomic()) {
105                 str += sformat(" %u,%u %ux%u -> %u,%u %ux%u",
106                                (uint32_t)p.get_prop_value("SRC_X") >> 16,
107                                (uint32_t)p.get_prop_value("SRC_Y") >> 16,
108                                (uint32_t)p.get_prop_value("SRC_W") >> 16,
109                                (uint32_t)p.get_prop_value("SRC_H") >> 16,
110                                (uint32_t)p.get_prop_value("CRTC_X"),
111                                (uint32_t)p.get_prop_value("CRTC_Y"),
112                                (uint32_t)p.get_prop_value("CRTC_W"),
113                                (uint32_t)p.get_prop_value("CRTC_H"));
114         }
116         string fmts = join<PixelFormat>(p.get_formats(), " ", [](PixelFormat fmt) { return PixelFormatToFourCC(fmt); });
118         str += sformat(" (%s)", fmts.c_str());
120         return str;
123 static string format_fb(Framebuffer& fb)
125         return sformat("FB %u %ux%u",
126                        fb.id(), fb.width(), fb.height());
129 static string format_property(const Property* prop, uint64_t val)
131         string ret = sformat("%s = ", prop->name().c_str());
133         switch (prop->type()) {
134         case PropertyType::Bitmask:
135         {
136                 vector<string> v, vall;
138                 for (auto kvp : prop->get_enums()) {
139                         if (val & (1 << kvp.first))
140                                 v.push_back(kvp.second);
141                         vall.push_back(sformat("%s=0x%x", kvp.second.c_str(), 1 << kvp.first));
142                 }
144                 ret += sformat("0x%" PRIx64 " (%s) [%s]", val, join(v, "|").c_str(), join(vall, "|").c_str());
146                 break;
147         }
149         case PropertyType::Blob:
150         {
151                 uint32_t blob_id = (uint32_t)val;
153                 if (blob_id) {
154                         Blob blob(prop->card(), blob_id);
155                         auto data = blob.data();
157                         ret += sformat("blob-id %u len %zu", blob_id, data.size());
158                 } else {
159                         ret += sformat("blob-id %u", blob_id);
160                 }
162                 break;
163         }
165         case PropertyType::Enum:
166         {
167                 string cur;
168                 vector<string> vall;
170                 for (auto kvp : prop->get_enums()) {
171                         if (val == kvp.first)
172                                 cur = kvp.second;
173                         vall.push_back(sformat("%s=%" PRIu64, kvp.second.c_str(), kvp.first));
174                 }
176                 ret += sformat("%" PRIu64 " (%s) [%s]", val, cur.c_str(), join(vall, "|").c_str());
178                 break;
179         }
181         case PropertyType::Object:
182         {
183                 ret += sformat("object id %u", (uint32_t)val);
184                 break;
185         }
187         case PropertyType::Range:
188         {
189                 auto values = prop->get_values();
191                 ret += sformat("%" PRIu64 " [%" PRIu64 " - %" PRIu64 "]",
192                                val, values[0], values[1]);
194                 break;
195         }
197         case PropertyType::SignedRange:
198         {
199                 auto values = prop->get_values();
201                 ret += sformat("%" PRIi64 " [%" PRIi64 " - %" PRIi64 "]",
202                                (int64_t)val, (int64_t)values[0], (int64_t)values[1]);
204                 break;
205         }
207         }
209         if (prop->is_pending())
210                 ret += " (pending)";
211         if (prop->is_immutable())
212                 ret += " (immutable)";
214         return ret;
217 static vector<string> format_props(DrmPropObject* o)
219         vector<string> lines;
221         auto pmap = o->get_prop_map();
222         for (auto pp : pmap) {
223                 const Property* p = o->card().get_prop(pp.first);
224                 lines.push_back(format_property(p, pp.second));
225         }
227         return lines;
230 static string format_ob(DrmObject* ob)
232         if (auto o = dynamic_cast<Connector*>(ob))
233                 return format_connector(*o);
234         else if (auto o = dynamic_cast<Encoder*>(ob))
235                 return format_encoder(*o);
236         else if (auto o = dynamic_cast<Crtc*>(ob))
237                 return format_crtc(*o);
238         else if (auto o = dynamic_cast<Plane*>(ob))
239                 return format_plane(*o);
240         else if (auto o = dynamic_cast<Framebuffer*>(ob))
241                 return format_fb(*o);
242         else
243                 EXIT("Unkown DRM Object type\n");
246 template<class T>
247 vector<T> filter(const vector<T>& sequence, function<bool(T)> predicate)
249         vector<T> result;
251         for(auto it = sequence.begin(); it != sequence.end(); ++it)
252                 if(predicate(*it))
253                         result.push_back(*it);
255         return result;
258 struct Entry
260         string title;
261         vector<string> lines;
262         vector<Entry> children;
263 };
265 static Entry& add_entry(vector<Entry>& entries)
267         entries.emplace_back();
268         return entries.back();
270 /*
271 static bool on_tty()
273         return isatty(STDOUT_FILENO) > 0;
275 */
276 enum class TreeGlyphMode {
277         None,
278         ASCII,
279         UTF8,
280 };
282 static TreeGlyphMode s_glyph_mode = TreeGlyphMode::None;
284 enum class TreeGlyph {
285         Vertical,
286         Branch,
287         Right,
288         Space,
289 };
291 static const map<TreeGlyph, string> glyphs_utf8 = {
292         { TreeGlyph::Vertical, "│ " },
293         { TreeGlyph::Branch, "├─" },
294         { TreeGlyph::Right, "└─" },
295         { TreeGlyph::Space, "  " },
297 };
299 static const map<TreeGlyph, string> glyphs_ascii = {
300         { TreeGlyph::Vertical, "| " },
301         { TreeGlyph::Branch, "|-" },
302         { TreeGlyph::Right, "`-" },
303         { TreeGlyph::Space, "  " },
305 };
307 const char* get_glyph(TreeGlyph glyph)
309         if (s_glyph_mode == TreeGlyphMode::None)
310                 return "  ";
312         const map<TreeGlyph, string>& glyphs = s_glyph_mode == TreeGlyphMode::UTF8 ? glyphs_utf8 : glyphs_ascii;
314         return glyphs.at(glyph).c_str();
317 static void print_entry(const Entry& e, const string& prefix, bool is_child, bool is_last)
319         string prefix1;
320         string prefix2;
322         if (is_child) {
323                 prefix1 = prefix + (is_last ? get_glyph(TreeGlyph::Right) : get_glyph(TreeGlyph::Branch));
324                 prefix2 = prefix + (is_last ? get_glyph(TreeGlyph::Space) : get_glyph(TreeGlyph::Vertical));
325         }
327         printf("%s%s\n", prefix1.c_str(), e.title.c_str());
329         bool has_children = e.children.size() > 0;
331         string data_prefix = prefix2 + (has_children ? get_glyph(TreeGlyph::Vertical) : get_glyph(TreeGlyph::Space));
333         for (const string& str : e.lines) {
334                 string p = data_prefix + get_glyph(TreeGlyph::Space);
335                 printf("%s%s\n", p.c_str(), str.c_str());
336         }
338         for (const Entry& child : e.children) {
339                 bool is_last = &child == &e.children.back();
341                 print_entry(child, prefix2, true, is_last);
342         }
345 static void print_entries(const vector<Entry>& entries, const string& prefix)
347         for (const Entry& e: entries) {
348                 print_entry(e, "", false, false);
349         }
352 template<class T>
353 static void append(vector<DrmObject*>& dst, const vector<T*>& src)
355         dst.insert(dst.end(), src.begin(), src.end());
359 static void print_as_list(Card& card)
361         vector<DrmPropObject*> obs;
362         vector<Framebuffer*> fbs;
364         for (Connector* conn : card.get_connectors()) {
365                 obs.push_back(conn);
366         }
368         for (Encoder* enc : card.get_encoders()) {
369                 obs.push_back(enc);
370         }
372         for (Crtc* crtc : card.get_crtcs()) {
373                 obs.push_back(crtc);
374                 if (crtc->buffer_id() && !card.has_has_universal_planes()) {
375                         Framebuffer* fb = new Framebuffer(card, crtc->buffer_id());
376                         fbs.push_back(fb);
377                 }
378         }
380         for (Plane* plane : card.get_planes()) {
381                 obs.push_back(plane);
382                 if (plane->fb_id()) {
383                         Framebuffer* fb = new Framebuffer(card, plane->fb_id());
384                         fbs.push_back(fb);
385                 }
386         }
388         for (DrmPropObject* ob: obs) {
389                 printf("%s\n", format_ob(ob).c_str());
391                 if (s_opts.print_props) {
392                         for (string str : format_props(ob))
393                                 printf("    %s\n", str.c_str());
394                 }
395         }
397         for (Framebuffer* fb: fbs) {
398                 printf("%s\n", format_ob(fb).c_str());
399         }
402 static void print_as_tree(Card& card)
404         vector<Entry> entries;
406         for (Connector* conn : card.get_connectors()) {
407                 if (!conn->connected())
408                         continue;
410                 Entry& e1 = add_entry(entries);
411                 e1.title = format_ob(conn);
412                 if (s_opts.print_props)
413                         e1.lines = format_props(conn);
415                 for (Encoder* enc : conn->get_encoders()) {
417                         Entry& e2 = add_entry(e1.children);
418                         e2.title = format_ob(enc);
419                         if (s_opts.print_props)
420                                 e2.lines = format_props(enc);
422                         if (Crtc* crtc = enc->get_crtc()) {
423                                 Entry& e3 = add_entry(e2.children);
424                                 e3.title = format_ob(crtc);
425                                 if (s_opts.print_props)
426                                         e3.lines = format_props(crtc);
428                                 if (crtc->buffer_id() && !card.has_has_universal_planes()) {
429                                         Framebuffer fb(card, crtc->buffer_id());
430                                         Entry& e5 = add_entry(e3.children);
432                                         e5.title = format_ob(&fb);
433                                 }
435                                 for (Plane* plane : card.get_planes()) {
436                                         if (plane->crtc_id() != crtc->id())
437                                                 continue;
439                                         Entry& e4 = add_entry(e3.children);
440                                         e4.title = format_ob(plane);
441                                         if (s_opts.print_props)
442                                                 e4.lines = format_props(plane);
444                                         uint32_t fb_id = plane->fb_id();
445                                         if (fb_id) {
446                                                 Framebuffer fb(card, fb_id);
448                                                 Entry& e5 = add_entry(e4.children);
450                                                 e5.title = format_ob(&fb);
451                                         }
452                                 }
453                         }
454                 }
455         }
457         print_entries(entries, "");
460 static void print_modes(Card& card)
462         for (Connector* conn : card.get_connectors()) {
463                 if (!conn->connected())
464                         continue;
466                 printf("%s\n", format_ob(conn).c_str());
468                 auto modes = conn->get_modes();
469                 for (unsigned i = 0; i < modes.size(); ++i)
470                         printf("%s\n", format_mode(modes[i], i).c_str());
471         }
474 static const char* usage_str =
475                 "Usage: kmsprint [OPTIONS]\n\n"
476                 "Options:\n"
477                 "  -l, --list        Print list instead of tree\n"
478                 "  -m, --modes       Print modes\n"
479                 "      --xmode       Print modes using X modeline\n"
480                 "  -p, --props       Print properties\n"
481                 ;
483 static void usage()
485         puts(usage_str);
488 int main(int argc, char **argv)
490         string dev_path = "/dev/dri/card0";
492         OptionSet optionset = {
493                 Option("|device=", [&dev_path](string s)
494                 {
495                         dev_path = s;
496                 }),
497                 Option("l|list", []()
498                 {
499                         s_opts.print_list = true;
500                 }),
501                 Option("m|modes", []()
502                 {
503                         s_opts.print_modes = true;
504                 }),
505                 Option("p|props", []()
506                 {
507                         s_opts.print_props = true;
508                 }),
509                 Option("|xmode", []() {
510                         s_opts.x_modeline = true;
511                 }),
512                 Option("h|help", []()
513                 {
514                         usage();
515                         exit(-1);
516                 }),
517         };
519         optionset.parse(argc, argv);
521         if (optionset.params().size() > 0) {
522                 usage();
523                 exit(-1);
524         }
526         Card card(dev_path);
528         if (s_opts.print_modes) {
529                 print_modes(card);
530                 return 0;
531         }
533         if (s_opts.print_list)
534                 print_as_list(card);
535         else
536                 print_as_tree(card);