xref: /aosp_15_r20/external/libkmsxx/utils/kmsprint.cpp (revision f0687c8a10b3e371dbe09214db6664e37c283cca)
1*f0687c8aSRaman Tenneti #include <algorithm>
2*f0687c8aSRaman Tenneti #include <cinttypes>
3*f0687c8aSRaman Tenneti #include <cstdio>
4*f0687c8aSRaman Tenneti #include <iostream>
5*f0687c8aSRaman Tenneti #include <string>
6*f0687c8aSRaman Tenneti #include <unistd.h>
7*f0687c8aSRaman Tenneti #include <fmt/format.h>
8*f0687c8aSRaman Tenneti 
9*f0687c8aSRaman Tenneti #include <kms++/kms++.h>
10*f0687c8aSRaman Tenneti #include <kms++util/kms++util.h>
11*f0687c8aSRaman Tenneti 
12*f0687c8aSRaman Tenneti using namespace std;
13*f0687c8aSRaman Tenneti using namespace kms;
14*f0687c8aSRaman Tenneti 
15*f0687c8aSRaman Tenneti static struct {
16*f0687c8aSRaman Tenneti 	bool print_props;
17*f0687c8aSRaman Tenneti 	bool print_modes;
18*f0687c8aSRaman Tenneti 	bool print_list;
19*f0687c8aSRaman Tenneti 	bool x_modeline;
20*f0687c8aSRaman Tenneti } s_opts;
21*f0687c8aSRaman Tenneti 
format_mode(const Videomode & m,unsigned idx)22*f0687c8aSRaman Tenneti static string format_mode(const Videomode& m, unsigned idx)
23*f0687c8aSRaman Tenneti {
24*f0687c8aSRaman Tenneti 	string str;
25*f0687c8aSRaman Tenneti 
26*f0687c8aSRaman Tenneti 	str = fmt::format("  {:2} ", idx);
27*f0687c8aSRaman Tenneti 
28*f0687c8aSRaman Tenneti 	if (s_opts.x_modeline) {
29*f0687c8aSRaman Tenneti 		str += fmt::format("{:12} {:6} {:4} {:4} {:4} {:4} {:4} {:4} {:4} {:4} {:3} {:#x} {:#x}",
30*f0687c8aSRaman Tenneti 				   m.name,
31*f0687c8aSRaman Tenneti 				   m.clock,
32*f0687c8aSRaman Tenneti 				   m.hdisplay, m.hsync_start, m.hsync_end, m.htotal,
33*f0687c8aSRaman Tenneti 				   m.vdisplay, m.vsync_start, m.vsync_end, m.vtotal,
34*f0687c8aSRaman Tenneti 				   m.vrefresh,
35*f0687c8aSRaman Tenneti 				   m.flags,
36*f0687c8aSRaman Tenneti 				   m.type);
37*f0687c8aSRaman Tenneti 	} else {
38*f0687c8aSRaman Tenneti 		str += m.to_string_long_padded();
39*f0687c8aSRaman Tenneti 	}
40*f0687c8aSRaman Tenneti 
41*f0687c8aSRaman Tenneti 	return str;
42*f0687c8aSRaman Tenneti }
43*f0687c8aSRaman Tenneti 
format_mode_short(const Videomode & m)44*f0687c8aSRaman Tenneti static string format_mode_short(const Videomode& m)
45*f0687c8aSRaman Tenneti {
46*f0687c8aSRaman Tenneti 	return m.to_string_long();
47*f0687c8aSRaman Tenneti }
48*f0687c8aSRaman Tenneti 
format_connector(Connector & c)49*f0687c8aSRaman Tenneti static string format_connector(Connector& c)
50*f0687c8aSRaman Tenneti {
51*f0687c8aSRaman Tenneti 	string str;
52*f0687c8aSRaman Tenneti 
53*f0687c8aSRaman Tenneti 	str = fmt::format("Connector {} ({}) {}",
54*f0687c8aSRaman Tenneti 			  c.idx(), c.id(), c.fullname());
55*f0687c8aSRaman Tenneti 
56*f0687c8aSRaman Tenneti 	switch (c.connector_status()) {
57*f0687c8aSRaman Tenneti 	case ConnectorStatus::Connected:
58*f0687c8aSRaman Tenneti 		str += " (connected)";
59*f0687c8aSRaman Tenneti 		break;
60*f0687c8aSRaman Tenneti 	case ConnectorStatus::Disconnected:
61*f0687c8aSRaman Tenneti 		str += " (disconnected)";
62*f0687c8aSRaman Tenneti 		break;
63*f0687c8aSRaman Tenneti 	default:
64*f0687c8aSRaman Tenneti 		str += " (unknown)";
65*f0687c8aSRaman Tenneti 		break;
66*f0687c8aSRaman Tenneti 	}
67*f0687c8aSRaman Tenneti 
68*f0687c8aSRaman Tenneti 	return str;
69*f0687c8aSRaman Tenneti }
70*f0687c8aSRaman Tenneti 
format_encoder(Encoder & e)71*f0687c8aSRaman Tenneti static string format_encoder(Encoder& e)
72*f0687c8aSRaman Tenneti {
73*f0687c8aSRaman Tenneti 	return fmt::format("Encoder {} ({}) {}",
74*f0687c8aSRaman Tenneti 			   e.idx(), e.id(), e.get_encoder_type());
75*f0687c8aSRaman Tenneti }
76*f0687c8aSRaman Tenneti 
format_crtc(Crtc & c)77*f0687c8aSRaman Tenneti static string format_crtc(Crtc& c)
78*f0687c8aSRaman Tenneti {
79*f0687c8aSRaman Tenneti 	string str;
80*f0687c8aSRaman Tenneti 
81*f0687c8aSRaman Tenneti 	str = fmt::format("Crtc {} ({})", c.idx(), c.id());
82*f0687c8aSRaman Tenneti 
83*f0687c8aSRaman Tenneti 	if (c.mode_valid())
84*f0687c8aSRaman Tenneti 		str += " " + format_mode_short(c.mode());
85*f0687c8aSRaman Tenneti 
86*f0687c8aSRaman Tenneti 	return str;
87*f0687c8aSRaman Tenneti }
88*f0687c8aSRaman Tenneti 
format_plane(Plane & p)89*f0687c8aSRaman Tenneti static string format_plane(Plane& p)
90*f0687c8aSRaman Tenneti {
91*f0687c8aSRaman Tenneti 	string str;
92*f0687c8aSRaman Tenneti 
93*f0687c8aSRaman Tenneti 	str = fmt::format("Plane {} ({})", p.idx(), p.id());
94*f0687c8aSRaman Tenneti 
95*f0687c8aSRaman Tenneti 	if (p.fb_id())
96*f0687c8aSRaman Tenneti 		str += fmt::format(" fb-id: {}", p.fb_id());
97*f0687c8aSRaman Tenneti 
98*f0687c8aSRaman Tenneti 	string crtcs = join<Crtc*>(p.get_possible_crtcs(), " ", [](Crtc* crtc) { return to_string(crtc->idx()); });
99*f0687c8aSRaman Tenneti 
100*f0687c8aSRaman Tenneti 	str += fmt::format(" (crtcs: {})", crtcs);
101*f0687c8aSRaman Tenneti 
102*f0687c8aSRaman Tenneti 	if (p.card().has_atomic()) {
103*f0687c8aSRaman Tenneti 		str += fmt::format(" {},{} {}x{} -> {},{} {}x{}",
104*f0687c8aSRaman Tenneti 				   (uint32_t)p.get_prop_value("SRC_X") >> 16,
105*f0687c8aSRaman Tenneti 				   (uint32_t)p.get_prop_value("SRC_Y") >> 16,
106*f0687c8aSRaman Tenneti 				   (uint32_t)p.get_prop_value("SRC_W") >> 16,
107*f0687c8aSRaman Tenneti 				   (uint32_t)p.get_prop_value("SRC_H") >> 16,
108*f0687c8aSRaman Tenneti 				   (uint32_t)p.get_prop_value("CRTC_X"),
109*f0687c8aSRaman Tenneti 				   (uint32_t)p.get_prop_value("CRTC_Y"),
110*f0687c8aSRaman Tenneti 				   (uint32_t)p.get_prop_value("CRTC_W"),
111*f0687c8aSRaman Tenneti 				   (uint32_t)p.get_prop_value("CRTC_H"));
112*f0687c8aSRaman Tenneti 	}
113*f0687c8aSRaman Tenneti 
114*f0687c8aSRaman Tenneti 	string fmts = join<PixelFormat>(p.get_formats(), " ", [](PixelFormat fmt) { return PixelFormatToFourCC(fmt); });
115*f0687c8aSRaman Tenneti 
116*f0687c8aSRaman Tenneti 	str += fmt::format(" ({})", fmts);
117*f0687c8aSRaman Tenneti 
118*f0687c8aSRaman Tenneti 	return str;
119*f0687c8aSRaman Tenneti }
120*f0687c8aSRaman Tenneti 
format_fb(Framebuffer & fb)121*f0687c8aSRaman Tenneti static string format_fb(Framebuffer& fb)
122*f0687c8aSRaman Tenneti {
123*f0687c8aSRaman Tenneti 	return fmt::format("FB {} {}x{}",
124*f0687c8aSRaman Tenneti 			   fb.id(), fb.width(), fb.height());
125*f0687c8aSRaman Tenneti }
126*f0687c8aSRaman Tenneti 
format_property(const Property * prop,uint64_t val)127*f0687c8aSRaman Tenneti static string format_property(const Property* prop, uint64_t val)
128*f0687c8aSRaman Tenneti {
129*f0687c8aSRaman Tenneti 	string ret = fmt::format("{} ({}) = ", prop->name(), prop->id());
130*f0687c8aSRaman Tenneti 
131*f0687c8aSRaman Tenneti 	switch (prop->type()) {
132*f0687c8aSRaman Tenneti 	case PropertyType::Bitmask: {
133*f0687c8aSRaman Tenneti 		vector<string> v, vall;
134*f0687c8aSRaman Tenneti 
135*f0687c8aSRaman Tenneti 		for (auto kvp : prop->get_enums()) {
136*f0687c8aSRaman Tenneti 			if (val & (1 << kvp.first))
137*f0687c8aSRaman Tenneti 				v.push_back(kvp.second);
138*f0687c8aSRaman Tenneti 			vall.push_back(fmt::format("{}={:#x}", kvp.second, 1 << kvp.first));
139*f0687c8aSRaman Tenneti 		}
140*f0687c8aSRaman Tenneti 
141*f0687c8aSRaman Tenneti 		// XXX
142*f0687c8aSRaman Tenneti 		ret += fmt::format("{:#x} ({}) [{}]", val, join(v, "|"), join(vall, "|"));
143*f0687c8aSRaman Tenneti 
144*f0687c8aSRaman Tenneti 		break;
145*f0687c8aSRaman Tenneti 	}
146*f0687c8aSRaman Tenneti 
147*f0687c8aSRaman Tenneti 	case PropertyType::Blob: {
148*f0687c8aSRaman Tenneti 		uint32_t blob_id = (uint32_t)val;
149*f0687c8aSRaman Tenneti 
150*f0687c8aSRaman Tenneti 		if (blob_id) {
151*f0687c8aSRaman Tenneti 			Blob blob(prop->card(), blob_id);
152*f0687c8aSRaman Tenneti 			auto data = blob.data();
153*f0687c8aSRaman Tenneti 
154*f0687c8aSRaman Tenneti 			ret += fmt::format("blob-id {} len {}", blob_id, data.size());
155*f0687c8aSRaman Tenneti 		} else {
156*f0687c8aSRaman Tenneti 			ret += fmt::format("blob-id {}", blob_id);
157*f0687c8aSRaman Tenneti 		}
158*f0687c8aSRaman Tenneti 
159*f0687c8aSRaman Tenneti 		break;
160*f0687c8aSRaman Tenneti 	}
161*f0687c8aSRaman Tenneti 
162*f0687c8aSRaman Tenneti 	case PropertyType::Enum: {
163*f0687c8aSRaman Tenneti 		string cur;
164*f0687c8aSRaman Tenneti 		vector<string> vall;
165*f0687c8aSRaman Tenneti 
166*f0687c8aSRaman Tenneti 		for (auto kvp : prop->get_enums()) {
167*f0687c8aSRaman Tenneti 			if (val == kvp.first)
168*f0687c8aSRaman Tenneti 				cur = kvp.second;
169*f0687c8aSRaman Tenneti 			vall.push_back(fmt::format("{}={}", kvp.second, kvp.first));
170*f0687c8aSRaman Tenneti 		}
171*f0687c8aSRaman Tenneti 
172*f0687c8aSRaman Tenneti 		ret += fmt::format("{} ({}) [{}]", val, cur, join(vall, "|"));
173*f0687c8aSRaman Tenneti 
174*f0687c8aSRaman Tenneti 		break;
175*f0687c8aSRaman Tenneti 	}
176*f0687c8aSRaman Tenneti 
177*f0687c8aSRaman Tenneti 	case PropertyType::Object: {
178*f0687c8aSRaman Tenneti 		ret += fmt::format("object id {}", val);
179*f0687c8aSRaman Tenneti 		break;
180*f0687c8aSRaman Tenneti 	}
181*f0687c8aSRaman Tenneti 
182*f0687c8aSRaman Tenneti 	case PropertyType::Range: {
183*f0687c8aSRaman Tenneti 		auto values = prop->get_values();
184*f0687c8aSRaman Tenneti 
185*f0687c8aSRaman Tenneti 		ret += fmt::format("{} [{} - {}]",
186*f0687c8aSRaman Tenneti 				   val, values[0], values[1]);
187*f0687c8aSRaman Tenneti 
188*f0687c8aSRaman Tenneti 		break;
189*f0687c8aSRaman Tenneti 	}
190*f0687c8aSRaman Tenneti 
191*f0687c8aSRaman Tenneti 	case PropertyType::SignedRange: {
192*f0687c8aSRaman Tenneti 		auto values = prop->get_values();
193*f0687c8aSRaman Tenneti 
194*f0687c8aSRaman Tenneti 		ret += fmt::format("{} [{} - {}]",
195*f0687c8aSRaman Tenneti 				   (int64_t)val, (int64_t)values[0], (int64_t)values[1]);
196*f0687c8aSRaman Tenneti 
197*f0687c8aSRaman Tenneti 		break;
198*f0687c8aSRaman Tenneti 	}
199*f0687c8aSRaman Tenneti 	}
200*f0687c8aSRaman Tenneti 
201*f0687c8aSRaman Tenneti 	if (prop->is_pending())
202*f0687c8aSRaman Tenneti 		ret += " (pending)";
203*f0687c8aSRaman Tenneti 	if (prop->is_immutable())
204*f0687c8aSRaman Tenneti 		ret += " (immutable)";
205*f0687c8aSRaman Tenneti 
206*f0687c8aSRaman Tenneti 	return ret;
207*f0687c8aSRaman Tenneti }
208*f0687c8aSRaman Tenneti 
format_props(DrmPropObject * o)209*f0687c8aSRaman Tenneti static vector<string> format_props(DrmPropObject* o)
210*f0687c8aSRaman Tenneti {
211*f0687c8aSRaman Tenneti 	vector<string> lines;
212*f0687c8aSRaman Tenneti 
213*f0687c8aSRaman Tenneti 	auto pmap = o->get_prop_map();
214*f0687c8aSRaman Tenneti 	for (auto pp : pmap) {
215*f0687c8aSRaman Tenneti 		const Property* p = o->card().get_prop(pp.first);
216*f0687c8aSRaman Tenneti 		lines.push_back(format_property(p, pp.second));
217*f0687c8aSRaman Tenneti 	}
218*f0687c8aSRaman Tenneti 
219*f0687c8aSRaman Tenneti 	return lines;
220*f0687c8aSRaman Tenneti }
221*f0687c8aSRaman Tenneti 
format_ob(DrmObject * ob)222*f0687c8aSRaman Tenneti static string format_ob(DrmObject* ob)
223*f0687c8aSRaman Tenneti {
224*f0687c8aSRaman Tenneti 	if (auto o = dynamic_cast<Connector*>(ob))
225*f0687c8aSRaman Tenneti 		return format_connector(*o);
226*f0687c8aSRaman Tenneti 	else if (auto o = dynamic_cast<Encoder*>(ob))
227*f0687c8aSRaman Tenneti 		return format_encoder(*o);
228*f0687c8aSRaman Tenneti 	else if (auto o = dynamic_cast<Crtc*>(ob))
229*f0687c8aSRaman Tenneti 		return format_crtc(*o);
230*f0687c8aSRaman Tenneti 	else if (auto o = dynamic_cast<Plane*>(ob))
231*f0687c8aSRaman Tenneti 		return format_plane(*o);
232*f0687c8aSRaman Tenneti 	else if (auto o = dynamic_cast<Framebuffer*>(ob))
233*f0687c8aSRaman Tenneti 		return format_fb(*o);
234*f0687c8aSRaman Tenneti 	else
235*f0687c8aSRaman Tenneti 		EXIT("Unkown DRM Object type\n");
236*f0687c8aSRaman Tenneti }
237*f0687c8aSRaman Tenneti 
238*f0687c8aSRaman Tenneti template<class T>
filter(const vector<T> & sequence,function<bool (T)> predicate)239*f0687c8aSRaman Tenneti vector<T> filter(const vector<T>& sequence, function<bool(T)> predicate)
240*f0687c8aSRaman Tenneti {
241*f0687c8aSRaman Tenneti 	vector<T> result;
242*f0687c8aSRaman Tenneti 
243*f0687c8aSRaman Tenneti 	for (auto it = sequence.begin(); it != sequence.end(); ++it)
244*f0687c8aSRaman Tenneti 		if (predicate(*it))
245*f0687c8aSRaman Tenneti 			result.push_back(*it);
246*f0687c8aSRaman Tenneti 
247*f0687c8aSRaman Tenneti 	return result;
248*f0687c8aSRaman Tenneti }
249*f0687c8aSRaman Tenneti 
250*f0687c8aSRaman Tenneti struct Entry {
251*f0687c8aSRaman Tenneti 	string title;
252*f0687c8aSRaman Tenneti 	vector<string> lines;
253*f0687c8aSRaman Tenneti 	vector<Entry> children;
254*f0687c8aSRaman Tenneti };
255*f0687c8aSRaman Tenneti 
add_entry(vector<Entry> & entries)256*f0687c8aSRaman Tenneti static Entry& add_entry(vector<Entry>& entries)
257*f0687c8aSRaman Tenneti {
258*f0687c8aSRaman Tenneti 	entries.emplace_back();
259*f0687c8aSRaman Tenneti 	return entries.back();
260*f0687c8aSRaman Tenneti }
261*f0687c8aSRaman Tenneti /*
262*f0687c8aSRaman Tenneti static bool on_tty()
263*f0687c8aSRaman Tenneti {
264*f0687c8aSRaman Tenneti 	return isatty(STDOUT_FILENO) > 0;
265*f0687c8aSRaman Tenneti }
266*f0687c8aSRaman Tenneti */
267*f0687c8aSRaman Tenneti enum class TreeGlyphMode {
268*f0687c8aSRaman Tenneti 	None,
269*f0687c8aSRaman Tenneti 	ASCII,
270*f0687c8aSRaman Tenneti 	UTF8,
271*f0687c8aSRaman Tenneti };
272*f0687c8aSRaman Tenneti 
273*f0687c8aSRaman Tenneti static TreeGlyphMode s_glyph_mode = TreeGlyphMode::None;
274*f0687c8aSRaman Tenneti 
275*f0687c8aSRaman Tenneti enum class TreeGlyph {
276*f0687c8aSRaman Tenneti 	Vertical,
277*f0687c8aSRaman Tenneti 	Branch,
278*f0687c8aSRaman Tenneti 	Right,
279*f0687c8aSRaman Tenneti 	Space,
280*f0687c8aSRaman Tenneti };
281*f0687c8aSRaman Tenneti 
282*f0687c8aSRaman Tenneti static const map<TreeGlyph, string> glyphs_utf8 = {
283*f0687c8aSRaman Tenneti 	{ TreeGlyph::Vertical, "│ " },
284*f0687c8aSRaman Tenneti 	{ TreeGlyph::Branch, "├─" },
285*f0687c8aSRaman Tenneti 	{ TreeGlyph::Right, "└─" },
286*f0687c8aSRaman Tenneti 	{ TreeGlyph::Space, "  " },
287*f0687c8aSRaman Tenneti 
288*f0687c8aSRaman Tenneti };
289*f0687c8aSRaman Tenneti 
290*f0687c8aSRaman Tenneti static const map<TreeGlyph, string> glyphs_ascii = {
291*f0687c8aSRaman Tenneti 	{ TreeGlyph::Vertical, "| " },
292*f0687c8aSRaman Tenneti 	{ TreeGlyph::Branch, "|-" },
293*f0687c8aSRaman Tenneti 	{ TreeGlyph::Right, "`-" },
294*f0687c8aSRaman Tenneti 	{ TreeGlyph::Space, "  " },
295*f0687c8aSRaman Tenneti 
296*f0687c8aSRaman Tenneti };
297*f0687c8aSRaman Tenneti 
get_glyph(TreeGlyph glyph)298*f0687c8aSRaman Tenneti const string& get_glyph(TreeGlyph glyph)
299*f0687c8aSRaman Tenneti {
300*f0687c8aSRaman Tenneti 	static const string s_empty = "  ";
301*f0687c8aSRaman Tenneti 
302*f0687c8aSRaman Tenneti 	if (s_glyph_mode == TreeGlyphMode::None)
303*f0687c8aSRaman Tenneti 		return s_empty;
304*f0687c8aSRaman Tenneti 
305*f0687c8aSRaman Tenneti 	const map<TreeGlyph, string>& glyphs = s_glyph_mode == TreeGlyphMode::UTF8 ? glyphs_utf8 : glyphs_ascii;
306*f0687c8aSRaman Tenneti 
307*f0687c8aSRaman Tenneti 	return glyphs.at(glyph);
308*f0687c8aSRaman Tenneti }
309*f0687c8aSRaman Tenneti 
print_entry(const Entry & e,const string & prefix,bool is_child,bool is_last)310*f0687c8aSRaman Tenneti static void print_entry(const Entry& e, const string& prefix, bool is_child, bool is_last)
311*f0687c8aSRaman Tenneti {
312*f0687c8aSRaman Tenneti 	string prefix1;
313*f0687c8aSRaman Tenneti 	string prefix2;
314*f0687c8aSRaman Tenneti 
315*f0687c8aSRaman Tenneti 	if (is_child) {
316*f0687c8aSRaman Tenneti 		prefix1 = prefix + (is_last ? get_glyph(TreeGlyph::Right) : get_glyph(TreeGlyph::Branch));
317*f0687c8aSRaman Tenneti 		prefix2 = prefix + (is_last ? get_glyph(TreeGlyph::Space) : get_glyph(TreeGlyph::Vertical));
318*f0687c8aSRaman Tenneti 	}
319*f0687c8aSRaman Tenneti 
320*f0687c8aSRaman Tenneti 	fmt::print("{}{}\n", prefix1, e.title);
321*f0687c8aSRaman Tenneti 
322*f0687c8aSRaman Tenneti 	bool has_children = e.children.size() > 0;
323*f0687c8aSRaman Tenneti 
324*f0687c8aSRaman Tenneti 	string data_prefix = prefix2 + (has_children ? get_glyph(TreeGlyph::Vertical) : get_glyph(TreeGlyph::Space));
325*f0687c8aSRaman Tenneti 
326*f0687c8aSRaman Tenneti 	for (const string& str : e.lines) {
327*f0687c8aSRaman Tenneti 		string p = data_prefix + get_glyph(TreeGlyph::Space);
328*f0687c8aSRaman Tenneti 		fmt::print("{}{}\n", p, str);
329*f0687c8aSRaman Tenneti 	}
330*f0687c8aSRaman Tenneti 
331*f0687c8aSRaman Tenneti 	for (const Entry& child : e.children) {
332*f0687c8aSRaman Tenneti 		bool is_last = &child == &e.children.back();
333*f0687c8aSRaman Tenneti 
334*f0687c8aSRaman Tenneti 		print_entry(child, prefix2, true, is_last);
335*f0687c8aSRaman Tenneti 	}
336*f0687c8aSRaman Tenneti }
337*f0687c8aSRaman Tenneti 
print_entries(const vector<Entry> & entries,const string & prefix)338*f0687c8aSRaman Tenneti static void print_entries(const vector<Entry>& entries, const string& prefix)
339*f0687c8aSRaman Tenneti {
340*f0687c8aSRaman Tenneti 	for (const Entry& e : entries) {
341*f0687c8aSRaman Tenneti 		print_entry(e, "", false, false);
342*f0687c8aSRaman Tenneti 	}
343*f0687c8aSRaman Tenneti }
344*f0687c8aSRaman Tenneti 
345*f0687c8aSRaman Tenneti template<class T>
append(vector<DrmObject * > & dst,const vector<T * > & src)346*f0687c8aSRaman Tenneti static void append(vector<DrmObject*>& dst, const vector<T*>& src)
347*f0687c8aSRaman Tenneti {
348*f0687c8aSRaman Tenneti 	dst.insert(dst.end(), src.begin(), src.end());
349*f0687c8aSRaman Tenneti }
350*f0687c8aSRaman Tenneti 
print_as_list(Card & card)351*f0687c8aSRaman Tenneti static void print_as_list(Card& card)
352*f0687c8aSRaman Tenneti {
353*f0687c8aSRaman Tenneti 	vector<DrmPropObject*> obs;
354*f0687c8aSRaman Tenneti 	vector<Framebuffer*> fbs;
355*f0687c8aSRaman Tenneti 
356*f0687c8aSRaman Tenneti 	for (Connector* conn : card.get_connectors()) {
357*f0687c8aSRaman Tenneti 		obs.push_back(conn);
358*f0687c8aSRaman Tenneti 	}
359*f0687c8aSRaman Tenneti 
360*f0687c8aSRaman Tenneti 	for (Encoder* enc : card.get_encoders()) {
361*f0687c8aSRaman Tenneti 		obs.push_back(enc);
362*f0687c8aSRaman Tenneti 	}
363*f0687c8aSRaman Tenneti 
364*f0687c8aSRaman Tenneti 	for (Crtc* crtc : card.get_crtcs()) {
365*f0687c8aSRaman Tenneti 		obs.push_back(crtc);
366*f0687c8aSRaman Tenneti 		if (crtc->buffer_id() && !card.has_universal_planes()) {
367*f0687c8aSRaman Tenneti 			Framebuffer* fb = new Framebuffer(card, crtc->buffer_id());
368*f0687c8aSRaman Tenneti 			fbs.push_back(fb);
369*f0687c8aSRaman Tenneti 		}
370*f0687c8aSRaman Tenneti 	}
371*f0687c8aSRaman Tenneti 
372*f0687c8aSRaman Tenneti 	for (Plane* plane : card.get_planes()) {
373*f0687c8aSRaman Tenneti 		obs.push_back(plane);
374*f0687c8aSRaman Tenneti 		if (plane->fb_id()) {
375*f0687c8aSRaman Tenneti 			Framebuffer* fb = new Framebuffer(card, plane->fb_id());
376*f0687c8aSRaman Tenneti 			fbs.push_back(fb);
377*f0687c8aSRaman Tenneti 		}
378*f0687c8aSRaman Tenneti 	}
379*f0687c8aSRaman Tenneti 
380*f0687c8aSRaman Tenneti 	for (DrmPropObject* ob : obs) {
381*f0687c8aSRaman Tenneti 		fmt::print("{}\n", format_ob(ob));
382*f0687c8aSRaman Tenneti 
383*f0687c8aSRaman Tenneti 		if (s_opts.print_props) {
384*f0687c8aSRaman Tenneti 			for (string str : format_props(ob))
385*f0687c8aSRaman Tenneti 				fmt::print("    {}\n", str);
386*f0687c8aSRaman Tenneti 		}
387*f0687c8aSRaman Tenneti 	}
388*f0687c8aSRaman Tenneti 
389*f0687c8aSRaman Tenneti 	for (Framebuffer* fb : fbs) {
390*f0687c8aSRaman Tenneti 		fmt::print("{}\n", format_ob(fb));
391*f0687c8aSRaman Tenneti 	}
392*f0687c8aSRaman Tenneti }
393*f0687c8aSRaman Tenneti 
print_as_tree(Card & card)394*f0687c8aSRaman Tenneti static void print_as_tree(Card& card)
395*f0687c8aSRaman Tenneti {
396*f0687c8aSRaman Tenneti 	vector<Entry> entries;
397*f0687c8aSRaman Tenneti 
398*f0687c8aSRaman Tenneti 	for (Connector* conn : card.get_connectors()) {
399*f0687c8aSRaman Tenneti 		Entry& e1 = add_entry(entries);
400*f0687c8aSRaman Tenneti 		e1.title = format_ob(conn);
401*f0687c8aSRaman Tenneti 		if (s_opts.print_props)
402*f0687c8aSRaman Tenneti 			e1.lines = format_props(conn);
403*f0687c8aSRaman Tenneti 
404*f0687c8aSRaman Tenneti 		for (Encoder* enc : conn->get_encoders()) {
405*f0687c8aSRaman Tenneti 			Entry& e2 = add_entry(e1.children);
406*f0687c8aSRaman Tenneti 			e2.title = format_ob(enc);
407*f0687c8aSRaman Tenneti 			if (s_opts.print_props)
408*f0687c8aSRaman Tenneti 				e2.lines = format_props(enc);
409*f0687c8aSRaman Tenneti 
410*f0687c8aSRaman Tenneti 			if (Crtc* crtc = enc->get_crtc()) {
411*f0687c8aSRaman Tenneti 				Entry& e3 = add_entry(e2.children);
412*f0687c8aSRaman Tenneti 				e3.title = format_ob(crtc);
413*f0687c8aSRaman Tenneti 				if (s_opts.print_props)
414*f0687c8aSRaman Tenneti 					e3.lines = format_props(crtc);
415*f0687c8aSRaman Tenneti 
416*f0687c8aSRaman Tenneti 				if (crtc->buffer_id() && !card.has_universal_planes()) {
417*f0687c8aSRaman Tenneti 					Framebuffer fb(card, crtc->buffer_id());
418*f0687c8aSRaman Tenneti 					Entry& e5 = add_entry(e3.children);
419*f0687c8aSRaman Tenneti 
420*f0687c8aSRaman Tenneti 					e5.title = format_ob(&fb);
421*f0687c8aSRaman Tenneti 				}
422*f0687c8aSRaman Tenneti 
423*f0687c8aSRaman Tenneti 				for (Plane* plane : card.get_planes()) {
424*f0687c8aSRaman Tenneti 					if (plane->crtc_id() != crtc->id())
425*f0687c8aSRaman Tenneti 						continue;
426*f0687c8aSRaman Tenneti 
427*f0687c8aSRaman Tenneti 					Entry& e4 = add_entry(e3.children);
428*f0687c8aSRaman Tenneti 					e4.title = format_ob(plane);
429*f0687c8aSRaman Tenneti 					if (s_opts.print_props)
430*f0687c8aSRaman Tenneti 						e4.lines = format_props(plane);
431*f0687c8aSRaman Tenneti 
432*f0687c8aSRaman Tenneti 					uint32_t fb_id = plane->fb_id();
433*f0687c8aSRaman Tenneti 					if (fb_id) {
434*f0687c8aSRaman Tenneti 						Framebuffer fb(card, fb_id);
435*f0687c8aSRaman Tenneti 
436*f0687c8aSRaman Tenneti 						Entry& e5 = add_entry(e4.children);
437*f0687c8aSRaman Tenneti 
438*f0687c8aSRaman Tenneti 						e5.title = format_ob(&fb);
439*f0687c8aSRaman Tenneti 					}
440*f0687c8aSRaman Tenneti 				}
441*f0687c8aSRaman Tenneti 			}
442*f0687c8aSRaman Tenneti 		}
443*f0687c8aSRaman Tenneti 	}
444*f0687c8aSRaman Tenneti 
445*f0687c8aSRaman Tenneti 	print_entries(entries, "");
446*f0687c8aSRaman Tenneti }
447*f0687c8aSRaman Tenneti 
print_modes(Card & card)448*f0687c8aSRaman Tenneti static void print_modes(Card& card)
449*f0687c8aSRaman Tenneti {
450*f0687c8aSRaman Tenneti 	for (Connector* conn : card.get_connectors()) {
451*f0687c8aSRaman Tenneti 		if (!conn->connected())
452*f0687c8aSRaman Tenneti 			continue;
453*f0687c8aSRaman Tenneti 
454*f0687c8aSRaman Tenneti 		fmt::print("{}\n", format_ob(conn));
455*f0687c8aSRaman Tenneti 
456*f0687c8aSRaman Tenneti 		auto modes = conn->get_modes();
457*f0687c8aSRaman Tenneti 		for (unsigned i = 0; i < modes.size(); ++i)
458*f0687c8aSRaman Tenneti 			fmt::print("{}\n", format_mode(modes[i], i));
459*f0687c8aSRaman Tenneti 	}
460*f0687c8aSRaman Tenneti }
461*f0687c8aSRaman Tenneti 
462*f0687c8aSRaman Tenneti static const char* usage_str =
463*f0687c8aSRaman Tenneti 	"Usage: kmsprint [OPTIONS]\n\n"
464*f0687c8aSRaman Tenneti 	"Options:\n"
465*f0687c8aSRaman Tenneti 	"      --device=DEVICE     DEVICE is the path to DRM card to open\n"
466*f0687c8aSRaman Tenneti 	"  -l, --list              Print list instead of tree\n"
467*f0687c8aSRaman Tenneti 	"  -m, --modes             Print modes\n"
468*f0687c8aSRaman Tenneti 	"      --xmode             Print modes using X modeline\n"
469*f0687c8aSRaman Tenneti 	"  -p, --props             Print properties\n";
470*f0687c8aSRaman Tenneti 
usage()471*f0687c8aSRaman Tenneti static void usage()
472*f0687c8aSRaman Tenneti {
473*f0687c8aSRaman Tenneti 	puts(usage_str);
474*f0687c8aSRaman Tenneti }
475*f0687c8aSRaman Tenneti 
main(int argc,char ** argv)476*f0687c8aSRaman Tenneti int main(int argc, char** argv)
477*f0687c8aSRaman Tenneti {
478*f0687c8aSRaman Tenneti 	string dev_path;
479*f0687c8aSRaman Tenneti 
480*f0687c8aSRaman Tenneti 	OptionSet optionset = {
481*f0687c8aSRaman Tenneti 		Option("|device=", [&dev_path](string s) {
482*f0687c8aSRaman Tenneti 			dev_path = s;
483*f0687c8aSRaman Tenneti 		}),
484*f0687c8aSRaman Tenneti 		Option("l|list", []() {
485*f0687c8aSRaman Tenneti 			s_opts.print_list = true;
486*f0687c8aSRaman Tenneti 		}),
487*f0687c8aSRaman Tenneti 		Option("m|modes", []() {
488*f0687c8aSRaman Tenneti 			s_opts.print_modes = true;
489*f0687c8aSRaman Tenneti 		}),
490*f0687c8aSRaman Tenneti 		Option("p|props", []() {
491*f0687c8aSRaman Tenneti 			s_opts.print_props = true;
492*f0687c8aSRaman Tenneti 		}),
493*f0687c8aSRaman Tenneti 		Option("|xmode", []() {
494*f0687c8aSRaman Tenneti 			s_opts.x_modeline = true;
495*f0687c8aSRaman Tenneti 		}),
496*f0687c8aSRaman Tenneti 		Option("h|help", []() {
497*f0687c8aSRaman Tenneti 			usage();
498*f0687c8aSRaman Tenneti 			exit(-1);
499*f0687c8aSRaman Tenneti 		}),
500*f0687c8aSRaman Tenneti 	};
501*f0687c8aSRaman Tenneti 
502*f0687c8aSRaman Tenneti 	optionset.parse(argc, argv);
503*f0687c8aSRaman Tenneti 
504*f0687c8aSRaman Tenneti 	if (optionset.params().size() > 0) {
505*f0687c8aSRaman Tenneti 		usage();
506*f0687c8aSRaman Tenneti 		exit(-1);
507*f0687c8aSRaman Tenneti 	}
508*f0687c8aSRaman Tenneti 
509*f0687c8aSRaman Tenneti 	Card card(dev_path);
510*f0687c8aSRaman Tenneti 
511*f0687c8aSRaman Tenneti 	if (s_opts.print_modes) {
512*f0687c8aSRaman Tenneti 		print_modes(card);
513*f0687c8aSRaman Tenneti 		return 0;
514*f0687c8aSRaman Tenneti 	}
515*f0687c8aSRaman Tenneti 
516*f0687c8aSRaman Tenneti 	if (s_opts.print_list)
517*f0687c8aSRaman Tenneti 		print_as_list(card);
518*f0687c8aSRaman Tenneti 	else
519*f0687c8aSRaman Tenneti 		print_as_tree(card);
520*f0687c8aSRaman Tenneti }
521