From cefd494924d24e114065d921c2e7718b806f0820 Mon Sep 17 00:00:00 2001
From: Tomi Valkeinen <tomi.valkeinen@ti.com>
Date: Sun, 29 May 2016 16:53:16 +0300
Subject: kmsprint: rewrite kmsprint

---
 utils/kmsprint.cpp | 562 +++++++++++++++++++++++++++++++++++++++++------------
 1 file changed, 438 insertions(+), 124 deletions(-)

diff --git a/utils/kmsprint.cpp b/utils/kmsprint.cpp
index a57d33f..cecba5c 100644
--- a/utils/kmsprint.cpp
+++ b/utils/kmsprint.cpp
@@ -1,142 +1,481 @@
 #include <cstdio>
 #include <algorithm>
 #include <iostream>
+#include <string>
+#include <unistd.h>
+#include <inttypes.h>
 
 #include "kms++.h"
 #include "opts.h"
+#include "kms++util.h"
+#include "strhelpers.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;
 
-string width(int w, string str)
+static string format_mode(const Videomode& m, unsigned idx)
 {
-	str.resize(w, ' ');
+	string str;
+
+	str = sformat("  %2u ", idx);
+
+	if (s_opts.x_modeline) {
+		str += sformat("%12s %6d %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 %6d %-16s %-16s %2u %#10x %#6x",
+			       m.name.c_str(),
+			       m.clock,
+			       h.c_str(), v.c_str(),
+			       m.vrefresh,
+			       m.flags,
+			       m.type);
+	}
+
 	return str;
 }
 
-void print_mode(const Videomode &m, int ind)
+static string format_mode_short(const Videomode& m)
 {
-	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);
+	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 %d %s %s %u",
+		       m.name.c_str(),
+		       m.clock,
+		       h.c_str(), v.c_str(),
+		       m.vrefresh);
 }
 
-void print_property(uint64_t val, const Property& p, int ind)
+static string format_connector(Connector& 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("Connector %u (%u) %s",
+		      c.idx(), c.id(), c.fullname().c_str());
+
+	if (c.connected())
+		str += " (connected)";
+
+	return str;
 }
 
-void print_properties(DrmPropObject& o, int ind)
+static string format_encoder(Encoder& e)
 {
-	auto pmap = o.get_prop_map();
-	printf("%sProperties, %u in total:\n", width(ind, "").c_str(),
-	       (unsigned) pmap.size());
+	return sformat("Encoder %u (%u) %s",
+		       e.idx(), e.id(), e.get_encoder_type().c_str());
+}
+
+static string format_crtc(Crtc& c)
+{
+	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());
+
+	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"));
+	}
+
+	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(kvp.second);
+		}
+
+		ret += sformat("%s (%s)", 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(kvp.second);
+		}
+
+		ret += sformat("%s (%s)", 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;
+}
+
+static vector<string> format_props(DrmPropObject* o)
+{
+	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;
+}
+
+static string format_ob(DrmObject* ob)
+{
+	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");
 }
 
-void print_plane(Plane& p, int ind)
+template<class T>
+vector<T> filter(const vector<T>& sequence, function<bool(T)> predicate)
 {
-	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");
+	vector<T> result;
+
+	for(auto it = sequence.begin(); it != sequence.end(); ++it)
+		if(predicate(*it))
+			result.push_back(*it);
 
-	if (opts.print_props)
-		print_properties(p, ind+2);
+	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);
+	}
+}
+
+template<class T>
+static void append(vector<DrmObject*>& dst, const vector<T*>& src)
+{
+	dst.insert(dst.end(), src.begin(), src.end());
+}
+
+
+static void print_as_list(Card& card)
+{
+	vector<DrmPropObject*> obs;
+	vector<Framebuffer*> fbs;
+
+	for (Connector* conn : card.get_connectors()) {
+		obs.push_back(conn);
+	}
 
-	if (opts.print_props)
-		print_properties(c, ind+2);
+	for (Encoder* enc : card.get_encoders()) {
+		obs.push_back(enc);
+	}
 
-	if (opts.recurse)
-		for (auto enc : c.get_encoders())
-			print_encoder(*enc, ind + 2);
+	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);
+		}
+	}
 
-	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);
+	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()) {
+		if (!conn->connected())
+			continue;
+
+		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 +485,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 +521,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);
 }
-- 
cgit v1.2.3