summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoman Kovalivskyi <roman.kovalivskyi@globallogic.com>2019-11-04 17:54:31 +0200
committerRoman Kovalivskyi <roman.kovalivskyi@globallogic.com>2019-11-21 23:18:07 +0000
commitd07c370592056ac25e1d5c666ba3845df8165dad (patch)
tree63afa5c0f8329355affd90dc5981ddba92001ab8
parentdf88299409b08cceb88885f02f64ddc9e492c210 (diff)
drm_hwcomposer: Add property hwc.drm.primary_display_order
There are cases when primary display lookup order should be overriden. This could be achieved with adding system property hwc.drm.primary_display_order. Example of primary_display_order property usage: hwc.drm.primary_display_order=HDMI-A-2,HDMI-A-1,... This means that first priority goes to HDMI-A-2 connector, then HDMI-A-1 connector, then everything else. Internal connectors have higher priority than any other connectors not mentioned in property. Connected connector with highest priority would be selected as a primary display. Signed-off-by: Roman Kovalivskyi <roman.kovalivskyi@globallogic.com>
-rw-r--r--drm/drmdevice.cpp109
1 files changed, 98 insertions, 11 deletions
diff --git a/drm/drmdevice.cpp b/drm/drmdevice.cpp
index 2007fdd..bcb9ddd 100644
--- a/drm/drmdevice.cpp
+++ b/drm/drmdevice.cpp
@@ -30,11 +30,91 @@
#include <xf86drmMode.h>
#include <cinttypes>
+#include <algorithm>
+#include <array>
+#include <string>
+
#include <cutils/properties.h>
#include <log/log.h>
+static void trim_left(std::string &str) {
+ str.erase(std::begin(str),
+ std::find_if(std::begin(str), std::end(str),
+ [](int ch) { return !std::isspace(ch); }));
+}
+
+static void trim_right(std::string &str) {
+ str.erase(std::find_if(std::rbegin(str), std::rend(str),
+ [](int ch) { return !std::isspace(ch); })
+ .base(),
+ std::end(str));
+}
+
+static void trim(std::string &str) {
+ trim_left(str);
+ trim_right(str);
+}
+
namespace android {
+static std::vector<std::string> read_primary_display_order_prop() {
+ std::array<char, PROPERTY_VALUE_MAX> display_order_buf;
+ property_get("hwc.drm.primary_display_order", display_order_buf.data(),
+ "...");
+
+ std::vector<std::string> display_order;
+ std::istringstream str(display_order_buf.data());
+ for (std::string conn_name = ""; std::getline(str, conn_name, ',');) {
+ trim(conn_name);
+ display_order.push_back(std::move(conn_name));
+ }
+ return display_order;
+}
+
+static std::vector<DrmConnector *> make_primary_display_candidates(
+ std::vector<std::unique_ptr<DrmConnector>> &connectors) {
+ std::vector<DrmConnector *> primary_candidates;
+ std::transform(std::begin(connectors), std::end(connectors),
+ std::back_inserter(primary_candidates),
+ [](std::unique_ptr<DrmConnector> &conn) {
+ return conn.get();
+ });
+ primary_candidates.erase(std::remove_if(std::begin(primary_candidates),
+ std::end(primary_candidates),
+ [](const DrmConnector *conn) {
+ return conn->state() !=
+ DRM_MODE_CONNECTED;
+ }),
+ std::end(primary_candidates));
+
+ std::vector<std::string> display_order = read_primary_display_order_prop();
+ bool use_other = display_order.back() == "...";
+
+ // putting connectors from primary_display_order first
+ auto curr_connector = std::begin(primary_candidates);
+ for (const std::string &display_name : display_order) {
+ auto it = std::find_if(std::begin(primary_candidates),
+ std::end(primary_candidates),
+ [&display_name](const DrmConnector *conn) {
+ return conn->name() == display_name;
+ });
+ if (it != std::end(primary_candidates)) {
+ std::iter_swap(it, curr_connector);
+ ++curr_connector;
+ }
+ }
+
+ if (use_other) {
+ // then putting internal connectors second, everything else afterwards
+ std::partition(curr_connector, std::end(primary_candidates),
+ [](const DrmConnector *conn) { return conn->internal(); });
+ } else {
+ primary_candidates.erase(curr_connector, std::end(primary_candidates));
+ }
+
+ return primary_candidates;
+}
+
DrmDevice::DrmDevice() : event_listener_(this) {
}
@@ -173,19 +253,26 @@ std::tuple<int, int> DrmDevice::Init(const char *path, int num_displays) {
connectors_.emplace_back(std::move(conn));
}
- // First look for primary amongst internal connectors
- for (auto &conn : connectors_) {
- if (conn->internal() && !found_primary) {
- conn->set_display(num_displays);
- displays_[num_displays] = num_displays;
- ++num_displays;
- found_primary = true;
- break;
- }
+ // Primary display priority:
+ // 1) hwc.drm.primary_display_order property
+ // 2) internal connectors
+ // 3) anything else
+ std::vector<DrmConnector *>
+ primary_candidates = make_primary_display_candidates(connectors_);
+ if (!primary_candidates.empty() && !found_primary) {
+ DrmConnector &conn = **std::begin(primary_candidates);
+ conn.set_display(num_displays);
+ displays_[num_displays] = num_displays;
+ ++num_displays;
+ found_primary = true;
+ } else {
+ ALOGE(
+ "Failed to find primary display from \"hwc.drm.primary_display_order\" "
+ "property");
}
- // Then pick first available as primary and for the others assign
- // consecutive display_numbers.
+ // If no priority display were found then pick first available as primary and
+ // for the others assign consecutive display_numbers.
for (auto &conn : connectors_) {
if (conn->external() || conn->internal()) {
if (!found_primary) {