diff options
author | Roman Kovalivskyi <roman.kovalivskyi@globallogic.com> | 2019-11-04 17:54:31 +0200 |
---|---|---|
committer | Roman Kovalivskyi <roman.kovalivskyi@globallogic.com> | 2019-11-21 23:18:07 +0000 |
commit | d07c370592056ac25e1d5c666ba3845df8165dad (patch) | |
tree | 63afa5c0f8329355affd90dc5981ddba92001ab8 | |
parent | df88299409b08cceb88885f02f64ddc9e492c210 (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.cpp | 109 |
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) { |