]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - android/external-libkmsxx.git/blobdiff - utils/kmsprint.cpp
kmsprint: print connectors even if disconnected
[android/external-libkmsxx.git] / utils / kmsprint.cpp
index 7b9de8c0f76c2fe18b7584fe5ca73a939a08d47d..4d355fc52c35aace85b485cf0af3a74d93f13b63 100644 (file)
-#include <cstdio>
 #include <algorithm>
+#include <cinttypes>
+#include <cstdio>
 #include <iostream>
+#include <string>
+#include <unistd.h>
 
-#include "kms++.h"
-#include "opts.h"
+#include <kms++/kms++.h>
+#include <kms++util/kms++util.h>
 
 using namespace std;
 using namespace kms;
 
-namespace kmsprint {
-
 static struct {
        bool print_props;
        bool print_modes;
-       bool recurse;
-} opts;
+       bool print_list;
+       bool x_modeline;
+} s_opts;
+
+static string format_mode(const Videomode& m, unsigned idx)
+{
+       string str;
+
+       str = sformat("  %2u ", idx);
+
+       if (s_opts.x_modeline) {
+               str += sformat("%12s %6u %4u %4u %4u %4u %4u %4u %4u %4u  %2u %#x %#x",
+                              m.name.c_str(),
+                              m.clock,
+                              m.hdisplay, m.hsync_start, m.hsync_end, m.htotal,
+                              m.vdisplay, m.vsync_start, m.vsync_end, m.vtotal,
+                              m.vrefresh,
+                              m.flags,
+                              m.type);
+       } else {
+               string h = sformat("%u/%u/%u/%u", m.hdisplay, m.hfp(), m.hsw(), m.hbp());
+               string v = sformat("%u/%u/%u/%u", m.vdisplay, m.vfp(), m.vsw(), m.vbp());
+
+               str += sformat("%-12s %7.3f %-16s %-16s %2u (%.2f) %#10x %#6x",
+                              m.name.c_str(),
+                              m.clock / 1000.0,
+                              h.c_str(), v.c_str(),
+                              m.vrefresh, m.calculated_vrefresh(),
+                              m.flags,
+                              m.type);
+       }
+
+       return str;
+}
 
-string width(int w, string str)
+static string format_mode_short(const Videomode& m)
 {
-       str.resize(w, ' ');
+       string h = sformat("%u/%u/%u/%u", m.hdisplay, m.hfp(), m.hsw(), m.hbp());
+       string v = sformat("%u/%u/%u/%u", m.vdisplay, m.vfp(), m.vsw(), m.vbp());
+
+       return sformat("%s %.3f %s %s %u (%.2f)",
+                      m.name.c_str(),
+                      m.clock / 1000.0,
+                      h.c_str(), v.c_str(),
+                      m.vrefresh, m.calculated_vrefresh());
+}
+
+static string format_connector(Connector& c)
+{
+       string str;
+
+       str = sformat("Connector %u (%u) %s",
+                     c.idx(), c.id(), c.fullname().c_str());
+
+       if (c.connected())
+               str += " (connected)";
+       else
+               str += " (disconnected)";
+
        return str;
 }
 
-void print_mode(const Videomode &m, int ind)
+static string format_encoder(Encoder& e)
 {
-       printf("%s%s %6d %4d %4d %4d %4d %d %4d %4d %4d %4d %d  %2d 0x%04x %2d\n",
-              width(ind, "").c_str(),
-              m.name[0] == '\0' ? "" : width(11, m.name).c_str(),
-              m.clock,
-              m.hdisplay,
-              m.hsync_start,
-              m.hsync_end,
-              m.htotal,
-              m.hskew,
-              m.vdisplay,
-              m.vsync_start,
-              m.vsync_end,
-              m.vtotal,
-              m.vscan,
-              m.vrefresh,
-              m.flags,
-              m.type);
+       return sformat("Encoder %u (%u) %s",
+                      e.idx(), e.id(), e.get_encoder_type().c_str());
 }
 
-void print_property(uint64_t val, const Property& p, int ind)
+static string format_crtc(Crtc& c)
 {
-       printf("%s%s (id %d) = %s\n", width(ind, "").c_str(),
-              p.name().c_str(), p.id(), p.to_str(val).c_str());
+       string str;
+
+       str = sformat("Crtc %u (%u)", c.idx(), c.id());
+
+       if (c.mode_valid())
+               str += " " + format_mode_short(c.mode());
+
+       return str;
+}
+
+static string format_plane(Plane& p)
+{
+       string str;
+
+       str = sformat("Plane %u (%u)", p.idx(), p.id());
+
+       if (p.fb_id())
+               str += sformat(" fb-id: %u", p.fb_id());
+
+       string crtcs = join<Crtc*>(p.get_possible_crtcs(), " ", [](Crtc* crtc) { return to_string(crtc->idx()); });
+
+       str += sformat(" (crtcs: %s)", crtcs.c_str());
+
+       if (p.card().has_atomic()) {
+               str += sformat(" %u,%u %ux%u -> %u,%u %ux%u",
+                              (uint32_t)p.get_prop_value("SRC_X") >> 16,
+                              (uint32_t)p.get_prop_value("SRC_Y") >> 16,
+                              (uint32_t)p.get_prop_value("SRC_W") >> 16,
+                              (uint32_t)p.get_prop_value("SRC_H") >> 16,
+                              (uint32_t)p.get_prop_value("CRTC_X"),
+                              (uint32_t)p.get_prop_value("CRTC_Y"),
+                              (uint32_t)p.get_prop_value("CRTC_W"),
+                              (uint32_t)p.get_prop_value("CRTC_H"));
+       }
+
+       string fmts = join<PixelFormat>(p.get_formats(), " ", [](PixelFormat fmt) { return PixelFormatToFourCC(fmt); });
+
+       str += sformat(" (%s)", fmts.c_str());
+
+       return str;
+}
+
+static string format_fb(Framebuffer& fb)
+{
+       return sformat("FB %u %ux%u",
+                      fb.id(), fb.width(), fb.height());
+}
+
+static string format_property(const Property* prop, uint64_t val)
+{
+       string ret = sformat("%s = ", prop->name().c_str());
+
+       switch (prop->type()) {
+       case PropertyType::Bitmask:
+       {
+               vector<string> v, vall;
+
+               for (auto kvp : prop->get_enums()) {
+                       if (val & (1 << kvp.first))
+                               v.push_back(kvp.second);
+                       vall.push_back(sformat("%s=0x%x", kvp.second.c_str(), 1 << kvp.first));
+               }
+
+               ret += sformat("0x%" PRIx64 " (%s) [%s]", val, join(v, "|").c_str(), join(vall, "|").c_str());
+
+               break;
+       }
+
+       case PropertyType::Blob:
+       {
+               uint32_t blob_id = (uint32_t)val;
+
+               if (blob_id) {
+                       Blob blob(prop->card(), blob_id);
+                       auto data = blob.data();
+
+                       ret += sformat("blob-id %u len %zu", blob_id, data.size());
+               } else {
+                       ret += sformat("blob-id %u", blob_id);
+               }
+
+               break;
+       }
+
+       case PropertyType::Enum:
+       {
+               string cur;
+               vector<string> vall;
+
+               for (auto kvp : prop->get_enums()) {
+                       if (val == kvp.first)
+                               cur = kvp.second;
+                       vall.push_back(sformat("%s=%" PRIu64, kvp.second.c_str(), kvp.first));
+               }
+
+               ret += sformat("%" PRIu64 " (%s) [%s]", val, cur.c_str(), join(vall, "|").c_str());
+
+               break;
+       }
+
+       case PropertyType::Object:
+       {
+               ret += sformat("object id %u", (uint32_t)val);
+               break;
+       }
+
+       case PropertyType::Range:
+       {
+               auto values = prop->get_values();
+
+               ret += sformat("%" PRIu64 " [%" PRIu64 " - %" PRIu64 "]",
+                              val, values[0], values[1]);
+
+               break;
+       }
+
+       case PropertyType::SignedRange:
+       {
+               auto values = prop->get_values();
+
+               ret += sformat("%" PRIi64 " [%" PRIi64 " - %" PRIi64 "]",
+                              (int64_t)val, (int64_t)values[0], (int64_t)values[1]);
+
+               break;
+       }
+
+       }
+
+       if (prop->is_pending())
+               ret += " (pending)";
+       if (prop->is_immutable())
+               ret += " (immutable)";
+
+       return ret;
 }
 
-void print_properties(DrmObject& o, int ind)
+static vector<string> format_props(DrmPropObject* o)
 {
-       auto pmap = o.get_prop_map();
-       printf("%sProperties, %u in total:\n", width(ind, "").c_str(),
-              (unsigned) pmap.size());
+       vector<string> lines;
+
+       auto pmap = o->get_prop_map();
        for (auto pp : pmap) {
-               const Property& p = *o.card().get_prop(pp.first);
-               print_property(pp.second, p, ind + 2);
+               const Property* p = o->card().get_prop(pp.first);
+               lines.push_back(format_property(p, pp.second));
        }
+
+       return lines;
 }
 
-void print_plane(Plane& p, int ind)
+static string format_ob(DrmObject* ob)
 {
-       printf("%sPlane Id %d %d,%d -> %dx%d formats:", width(ind, "").c_str(),
-              p.id(), p.crtc_x(), p.crtc_y(), p.x(), p.y());
-       for (auto f : p.get_formats())
-               printf(" %s", PixelFormatToFourCC(f).c_str());
-       printf("\n");
+       if (auto o = dynamic_cast<Connector*>(ob))
+               return format_connector(*o);
+       else if (auto o = dynamic_cast<Encoder*>(ob))
+               return format_encoder(*o);
+       else if (auto o = dynamic_cast<Crtc*>(ob))
+               return format_crtc(*o);
+       else if (auto o = dynamic_cast<Plane*>(ob))
+               return format_plane(*o);
+       else if (auto o = dynamic_cast<Framebuffer*>(ob))
+               return format_fb(*o);
+       else
+               EXIT("Unkown DRM Object type\n");
+}
 
-       if (opts.print_props)
-               print_properties(p, ind+2);
+template<class T>
+vector<T> filter(const vector<T>& sequence, function<bool(T)> predicate)
+{
+       vector<T> result;
+
+       for(auto it = sequence.begin(); it != sequence.end(); ++it)
+               if(predicate(*it))
+                       result.push_back(*it);
+
+       return result;
 }
 
-void print_crtc(Crtc& cc, int ind)
+struct Entry
 {
-       printf("%sCRTC Id %d BufferId %d %dx%d at %dx%d gamma_size %d\n",
-              width(ind, "").c_str(), cc.id(), cc.buffer_id(), cc.width(),
-              cc.height(), cc.x(), cc.y(), cc.gamma_size());
+       string title;
+       vector<string> lines;
+       vector<Entry> children;
+};
 
-       printf("%s   Mode ", width(ind, "").c_str());
-       print_mode(cc.mode(), 0);
+static Entry& add_entry(vector<Entry>& entries)
+{
+       entries.emplace_back();
+       return entries.back();
+}
+/*
+static bool on_tty()
+{
+       return isatty(STDOUT_FILENO) > 0;
+}
+*/
+enum class TreeGlyphMode {
+       None,
+       ASCII,
+       UTF8,
+};
+
+static TreeGlyphMode s_glyph_mode = TreeGlyphMode::None;
+
+enum class TreeGlyph {
+       Vertical,
+       Branch,
+       Right,
+       Space,
+};
+
+static const map<TreeGlyph, string> glyphs_utf8 = {
+       { TreeGlyph::Vertical, "│ " },
+       { TreeGlyph::Branch, "├─" },
+       { TreeGlyph::Right, "└─" },
+       { TreeGlyph::Space, "  " },
+
+};
+
+static const map<TreeGlyph, string> glyphs_ascii = {
+       { TreeGlyph::Vertical, "| " },
+       { TreeGlyph::Branch, "|-" },
+       { TreeGlyph::Right, "`-" },
+       { TreeGlyph::Space, "  " },
+
+};
+
+const char* get_glyph(TreeGlyph glyph)
+{
+       if (s_glyph_mode == TreeGlyphMode::None)
+               return "  ";
 
-       if (opts.print_props)
-               print_properties(cc, ind+2);
+       const map<TreeGlyph, string>& glyphs = s_glyph_mode == TreeGlyphMode::UTF8 ? glyphs_utf8 : glyphs_ascii;
 
-       if (opts.recurse)
-               for (auto p : cc.get_possible_planes())
-                       print_plane(*p, ind + 2);
+       return glyphs.at(glyph).c_str();
 }
 
-void print_encoder(Encoder& e, int ind)
+static void print_entry(const Entry& e, const string& prefix, bool is_child, bool is_last)
 {
-       printf("%sEncoder Id %d type %s\n", width(ind, "").c_str(),
-              e.id(), e.get_encoder_type().c_str());
+       string prefix1;
+       string prefix2;
 
-       if (opts.print_props)
-               print_properties(e, ind+2);
+       if (is_child) {
+               prefix1 = prefix + (is_last ? get_glyph(TreeGlyph::Right) : get_glyph(TreeGlyph::Branch));
+               prefix2 = prefix + (is_last ? get_glyph(TreeGlyph::Space) : get_glyph(TreeGlyph::Vertical));
+       }
 
-       if (opts.recurse)
-               for (auto cc : e.get_possible_crtcs())
-                       print_crtc(*cc, ind + 2);
+       printf("%s%s\n", prefix1.c_str(), e.title.c_str());
+
+       bool has_children = e.children.size() > 0;
+
+       string data_prefix = prefix2 + (has_children ? get_glyph(TreeGlyph::Vertical) : get_glyph(TreeGlyph::Space));
+
+       for (const string& str : e.lines) {
+               string p = data_prefix + get_glyph(TreeGlyph::Space);
+               printf("%s%s\n", p.c_str(), str.c_str());
+       }
+
+       for (const Entry& child : e.children) {
+               bool is_last = &child == &e.children.back();
+
+               print_entry(child, prefix2, true, is_last);
+       }
 }
 
-void print_connector(Connector& c, int ind)
+static void print_entries(const vector<Entry>& entries, const string& prefix)
 {
-       printf("%sConnector %s Id %d %sconnected", width(ind, "").c_str(),
-              c.fullname().c_str(), c.id(), c.connected() ? "" : "dis");
-       if (c.subpixel() != 0)
-               printf(" Subpixel: %s", c.subpixel_str().c_str());
-       printf("\n");
+       for (const Entry& e: entries) {
+               print_entry(e, "", false, false);
+       }
+}
 
-       if (opts.print_props)
-               print_properties(c, ind+2);
+template<class T>
+static void append(vector<DrmObject*>& dst, const vector<T*>& src)
+{
+       dst.insert(dst.end(), src.begin(), src.end());
+}
 
-       if (opts.recurse)
-               for (auto enc : c.get_encoders())
-                       print_encoder(*enc, ind + 2);
 
-       if (opts.print_modes) {
-               auto modes = c.get_modes();
-               printf("%sModes, %u in total:\n", width(ind + 2, "").c_str(),
-                      (unsigned) modes.size());
-               for (auto mode : modes)
-                       print_mode(mode, ind + 3);
+static void print_as_list(Card& card)
+{
+       vector<DrmPropObject*> obs;
+       vector<Framebuffer*> fbs;
+
+       for (Connector* conn : card.get_connectors()) {
+               obs.push_back(conn);
+       }
+
+       for (Encoder* enc : card.get_encoders()) {
+               obs.push_back(enc);
+       }
+
+       for (Crtc* crtc : card.get_crtcs()) {
+               obs.push_back(crtc);
+               if (crtc->buffer_id() && !card.has_has_universal_planes()) {
+                       Framebuffer* fb = new Framebuffer(card, crtc->buffer_id());
+                       fbs.push_back(fb);
+               }
+       }
+
+       for (Plane* plane : card.get_planes()) {
+               obs.push_back(plane);
+               if (plane->fb_id()) {
+                       Framebuffer* fb = new Framebuffer(card, plane->fb_id());
+                       fbs.push_back(fb);
+               }
+       }
+
+       for (DrmPropObject* ob: obs) {
+               printf("%s\n", format_ob(ob).c_str());
+
+               if (s_opts.print_props) {
+                       for (string str : format_props(ob))
+                               printf("    %s\n", str.c_str());
+               }
+       }
+
+       for (Framebuffer* fb: fbs) {
+               printf("%s\n", format_ob(fb).c_str());
        }
 }
 
+static void print_as_tree(Card& card)
+{
+       vector<Entry> entries;
+
+       for (Connector* conn : card.get_connectors()) {
+               Entry& e1 = add_entry(entries);
+               e1.title = format_ob(conn);
+               if (s_opts.print_props)
+                       e1.lines = format_props(conn);
+
+               for (Encoder* enc : conn->get_encoders()) {
+
+                       Entry& e2 = add_entry(e1.children);
+                       e2.title = format_ob(enc);
+                       if (s_opts.print_props)
+                               e2.lines = format_props(enc);
+
+                       if (Crtc* crtc = enc->get_crtc()) {
+                               Entry& e3 = add_entry(e2.children);
+                               e3.title = format_ob(crtc);
+                               if (s_opts.print_props)
+                                       e3.lines = format_props(crtc);
+
+                               if (crtc->buffer_id() && !card.has_has_universal_planes()) {
+                                       Framebuffer fb(card, crtc->buffer_id());
+                                       Entry& e5 = add_entry(e3.children);
+
+                                       e5.title = format_ob(&fb);
+                               }
+
+                               for (Plane* plane : card.get_planes()) {
+                                       if (plane->crtc_id() != crtc->id())
+                                               continue;
+
+                                       Entry& e4 = add_entry(e3.children);
+                                       e4.title = format_ob(plane);
+                                       if (s_opts.print_props)
+                                               e4.lines = format_props(plane);
+
+                                       uint32_t fb_id = plane->fb_id();
+                                       if (fb_id) {
+                                               Framebuffer fb(card, fb_id);
+
+                                               Entry& e5 = add_entry(e4.children);
+
+                                               e5.title = format_ob(&fb);
+                                       }
+                               }
+                       }
+               }
+       }
+
+       print_entries(entries, "");
 }
 
-using namespace kmsprint;
+static void print_modes(Card& card)
+{
+       for (Connector* conn : card.get_connectors()) {
+               if (!conn->connected())
+                       continue;
+
+               printf("%s\n", format_ob(conn).c_str());
+
+               auto modes = conn->get_modes();
+               for (unsigned i = 0; i < modes.size(); ++i)
+                       printf("%s\n", format_mode(modes[i], i).c_str());
+       }
+}
 
 static const char* usage_str =
                "Usage: kmsprint [OPTIONS]\n\n"
                "Options:\n"
+               "  -l, --list        Print list instead of tree\n"
                "  -m, --modes       Print modes\n"
+               "      --xmode       Print modes using X modeline\n"
                "  -p, --props       Print properties\n"
-               "  -r, --recurse     Recursively print all related objects\n"
-               "      --id=<ID>     Print object <ID>\n"
                ;
 
 static void usage()
@@ -146,33 +490,29 @@ static void usage()
 
 int main(int argc, char **argv)
 {
-       string dev_path;
-       unsigned id = 0;
+       string dev_path = "/dev/dri/card0";
 
        OptionSet optionset = {
-               Option("|device=",
-               [&](string s)
+               Option("|device=", [&dev_path](string s)
                {
                        dev_path = s;
                }),
-               Option("|id=",
-               [&](string s)
+               Option("l|list", []()
                {
-                       id = stoul(s);
+                       s_opts.print_list = true;
                }),
-               Option("p", [&](string s)
+               Option("m|modes", []()
                {
-                       opts.print_props = true;
+                       s_opts.print_modes = true;
                }),
-               Option("m", [&](string s)
+               Option("p|props", []()
                {
-                       opts.print_modes = true;
+                       s_opts.print_props = true;
                }),
-               Option("r", [&](string s)
-               {
-                       opts.recurse = true;
+               Option("|xmode", []() {
+                       s_opts.x_modeline = true;
                }),
-               Option("h|help", [&]()
+               Option("h|help", []()
                {
                        usage();
                        exit(-1);
@@ -186,36 +526,15 @@ int main(int argc, char **argv)
                exit(-1);
        }
 
-       Card card;
-
-       /* No options impliles recursion */
-       if (id == 0) {
-               opts.recurse = true;
-               for (auto conn : card.get_connectors())
-                       print_connector(*conn, 0);
-               return 0;
-       } else {
-               auto ob = card.get_object(id);
-               if (!ob) {
-                       cerr << "kmsprint" << ": Object id " <<
-                               id << " not found." << endl;
-                       return -1;
-               }
-
-               if (auto co = dynamic_cast<Connector*>(ob))
-                       print_connector(*co, 0);
-               else if (auto en = dynamic_cast<Encoder*>(ob))
-                       print_encoder(*en, 0);
-               else if (auto cr = dynamic_cast<Crtc*>(ob))
-                       print_crtc(*cr, 0);
-               else if (auto pl = dynamic_cast<Plane*>(ob))
-                       print_plane(*pl, 0);
-               else {
-                       cerr << "kmsprint" << ": Unkown DRM Object type" <<
-                               endl;
-                       return -1;
-               }
+       Card card(dev_path);
 
+       if (s_opts.print_modes) {
+               print_modes(card);
                return 0;
        }
+
+       if (s_opts.print_list)
+               print_as_list(card);
+       else
+               print_as_tree(card);
 }