diff options
Diffstat (limited to 'drm/DrmDevice.cpp')
-rw-r--r-- | drm/DrmDevice.cpp | 423 |
1 files changed, 75 insertions, 348 deletions
diff --git a/drm/DrmDevice.cpp b/drm/DrmDevice.cpp index 8245b78..fd4589e 100644 --- a/drm/DrmDevice.cpp +++ b/drm/DrmDevice.cpp @@ -22,148 +22,66 @@ #include <xf86drm.h> #include <xf86drmMode.h> -#include <algorithm> -#include <array> -#include <cerrno> #include <cinttypes> #include <cstdint> -#include <sstream> #include <string> +#include "drm/DrmAtomicStateManager.h" #include "drm/DrmPlane.h" #include "utils/log.h" #include "utils/properties.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) == 0; })); -} - -static void trim_right(std::string *str) { - str->erase(std::find_if(std::rbegin(*str), std::rend(*str), - [](int ch) { return std::isspace(ch) == 0; }) - .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("vendor.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( - const 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), - [](const 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() { - self.reset(this); - mDrmFbImporter = std::make_unique<DrmFbImporter>(self); + drm_fb_importer_ = std::make_unique<DrmFbImporter>(*this); } -// NOLINTNEXTLINE (readability-function-cognitive-complexity): Fixme -std::tuple<int, int> DrmDevice::Init(const char *path, int num_displays) { +auto DrmDevice::Init(const char *path) -> int { /* TODO: Use drmOpenControl here instead */ fd_ = UniqueFd(open(path, O_RDWR | O_CLOEXEC)); - if (fd() < 0) { + if (!fd_) { // NOLINTNEXTLINE(concurrency-mt-unsafe): Fixme ALOGE("Failed to open dri %s: %s", path, strerror(errno)); - return std::make_tuple(-ENODEV, 0); + return -ENODEV; } - int ret = drmSetClientCap(fd(), DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1); - if (ret) { + int ret = drmSetClientCap(GetFd(), DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1); + if (ret != 0) { ALOGE("Failed to set universal plane cap %d", ret); - return std::make_tuple(ret, 0); + return ret; } - ret = drmSetClientCap(fd(), DRM_CLIENT_CAP_ATOMIC, 1); - if (ret) { + ret = drmSetClientCap(GetFd(), DRM_CLIENT_CAP_ATOMIC, 1); + if (ret != 0) { ALOGE("Failed to set atomic cap %d", ret); - return std::make_tuple(ret, 0); + return ret; } #ifdef DRM_CLIENT_CAP_WRITEBACK_CONNECTORS - ret = drmSetClientCap(fd(), DRM_CLIENT_CAP_WRITEBACK_CONNECTORS, 1); - if (ret) { + ret = drmSetClientCap(GetFd(), DRM_CLIENT_CAP_WRITEBACK_CONNECTORS, 1); + if (ret != 0) { ALOGI("Failed to set writeback cap %d", ret); - ret = 0; } #endif uint64_t cap_value = 0; - if (drmGetCap(fd(), DRM_CAP_ADDFB2_MODIFIERS, &cap_value)) { + if (drmGetCap(GetFd(), DRM_CAP_ADDFB2_MODIFIERS, &cap_value) != 0) { ALOGW("drmGetCap failed. Fallback to no modifier support."); cap_value = 0; } HasAddFb2ModifiersSupport_ = cap_value != 0; - drmSetMaster(fd()); - if (!drmIsMaster(fd())) { + drmSetMaster(GetFd()); + if (drmIsMaster(GetFd()) == 0) { ALOGE("DRM/KMS master access required"); - return std::make_tuple(-EACCES, 0); + return -EACCES; } - auto res = MakeDrmModeResUnique(fd()); + auto res = MakeDrmModeResUnique(GetFd()); if (!res) { ALOGE("Failed to get DrmDevice resources"); - return std::make_tuple(-ENODEV, 0); + return -ENODEV; } min_resolution_ = std::pair<uint32_t, uint32_t>(res->min_width, @@ -171,264 +89,64 @@ std::tuple<int, int> DrmDevice::Init(const char *path, int num_displays) { max_resolution_ = std::pair<uint32_t, uint32_t>(res->max_width, res->max_height); - // Assumes that the primary display will always be in the first - // drm_device opened. - bool found_primary = num_displays != 0; - - for (int i = 0; !ret && i < res->count_crtcs; ++i) { - auto c = MakeDrmModeCrtcUnique(fd(), res->crtcs[i]); - if (!c) { - ALOGE("Failed to get crtc %d", res->crtcs[i]); - ret = -ENODEV; - break; - } - - std::unique_ptr<DrmCrtc> crtc(new DrmCrtc(this, c.get(), i)); - - ret = crtc->Init(); - if (ret) { - ALOGE("Failed to initialize crtc %d", res->crtcs[i]); - break; + for (int i = 0; i < res->count_crtcs; ++i) { + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) + auto crtc = DrmCrtc::CreateInstance(*this, res->crtcs[i], i); + if (crtc) { + crtcs_.emplace_back(std::move(crtc)); } - crtcs_.emplace_back(std::move(crtc)); } - std::vector<uint32_t> possible_clones; - for (int i = 0; !ret && i < res->count_encoders; ++i) { - auto e = MakeDrmModeEncoderUnique(fd(), res->encoders[i]); - if (!e) { - ALOGE("Failed to get encoder %d", res->encoders[i]); - ret = -ENODEV; - break; + for (int i = 0; i < res->count_encoders; ++i) { + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) + auto enc = DrmEncoder::CreateInstance(*this, res->encoders[i], i); + if (enc) { + encoders_.emplace_back(std::move(enc)); } - - std::vector<DrmCrtc *> possible_crtcs; - DrmCrtc *current_crtc = nullptr; - for (auto &crtc : crtcs_) { - if ((1 << crtc->pipe()) & e->possible_crtcs) - possible_crtcs.push_back(crtc.get()); - - if (crtc->id() == e->crtc_id) - current_crtc = crtc.get(); - } - - std::unique_ptr<DrmEncoder> enc( - new DrmEncoder(e.get(), current_crtc, possible_crtcs)); - possible_clones.push_back(e->possible_clones); - - encoders_.emplace_back(std::move(enc)); } - for (unsigned int i = 0; i < encoders_.size(); i++) { - for (unsigned int j = 0; j < encoders_.size(); j++) - if (possible_clones[i] & (1 << j)) - encoders_[i]->AddPossibleClone(encoders_[j].get()); - } - - for (int i = 0; !ret && i < res->count_connectors; ++i) { - auto c = MakeDrmModeConnectorUnique(fd(), res->connectors[i]); - if (!c) { - ALOGE("Failed to get connector %d", res->connectors[i]); - ret = -ENODEV; - break; - } - - std::vector<DrmEncoder *> possible_encoders; - DrmEncoder *current_encoder = nullptr; - for (int j = 0; j < c->count_encoders; ++j) { - for (auto &encoder : encoders_) { - if (encoder->id() == c->encoders[j]) - possible_encoders.push_back(encoder.get()); - if (encoder->id() == c->encoder_id) - current_encoder = encoder.get(); - } - } - - std::unique_ptr<DrmConnector> conn( - new DrmConnector(this, c.get(), current_encoder, possible_encoders)); + for (int i = 0; i < res->count_connectors; ++i) { + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) + auto conn = DrmConnector::CreateInstance(*this, res->connectors[i], i); - ret = conn->Init(); - if (ret) { - ALOGE("Init connector %d failed", res->connectors[i]); - break; + if (!conn) { + continue; } - if (conn->writeback()) + if (conn->IsWriteback()) { writeback_connectors_.emplace_back(std::move(conn)); - else + } else { connectors_.emplace_back(std::move(conn)); - } - - // Primary display priority: - // 1) vendor.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 " - "\"vendor.hwc.drm.primary_display_order\" property"); - } - - // 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) { - conn->set_display(num_displays); - displays_[num_displays] = num_displays; - found_primary = true; - ++num_displays; - } else if (conn->display() < 0) { - conn->set_display(num_displays); - displays_[num_displays] = num_displays; - ++num_displays; - } } } - // Catch-all for the above loops - if (ret) - return std::make_tuple(ret, 0); - - auto plane_res = MakeDrmModePlaneResUnique(fd()); + auto plane_res = MakeDrmModePlaneResUnique(GetFd()); if (!plane_res) { ALOGE("Failed to get plane resources"); - return std::make_tuple(-ENOENT, 0); + return -ENOENT; } for (uint32_t i = 0; i < plane_res->count_planes; ++i) { - auto p = MakeDrmModePlaneUnique(fd(), plane_res->planes[i]); - if (!p) { - ALOGE("Failed to get plane %d", plane_res->planes[i]); - ret = -ENODEV; - break; - } - - std::unique_ptr<DrmPlane> plane(new DrmPlane(this, p.get())); - - ret = plane->Init(); - if (ret) { - ALOGE("Init plane %d failed", plane_res->planes[i]); - break; - } - - planes_.emplace_back(std::move(plane)); - } - if (ret) - return std::make_tuple(ret, 0); - - for (auto &conn : connectors_) { - ret = CreateDisplayPipe(conn.get()); - if (ret) { - ALOGE("Failed CreateDisplayPipe %d with %d", conn->id(), ret); - return std::make_tuple(ret, 0); - } - } - return std::make_tuple(ret, displays_.size()); -} - -bool DrmDevice::HandlesDisplay(int display) const { - return displays_.find(display) != displays_.end(); -} - -DrmConnector *DrmDevice::GetConnectorForDisplay(int display) const { - for (const auto &conn : connectors_) { - if (conn->display() == display) - return conn.get(); - } - return nullptr; -} - -DrmCrtc *DrmDevice::GetCrtcForDisplay(int display) const { - for (const auto &crtc : crtcs_) { - if (crtc->display() == display) - return crtc.get(); - } - return nullptr; -} + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) + auto plane = DrmPlane::CreateInstance(*this, plane_res->planes[i]); -const std::vector<std::unique_ptr<DrmCrtc>> &DrmDevice::crtcs() const { - return crtcs_; -} - -uint32_t DrmDevice::next_mode_id() { - return ++mode_id_; -} - -int DrmDevice::TryEncoderForDisplay(int display, DrmEncoder *enc) { - /* First try to use the currently-bound crtc */ - DrmCrtc *crtc = enc->crtc(); - if (crtc && crtc->can_bind(display)) { - crtc->set_display(display); - enc->set_crtc(crtc); - return 0; - } - - /* Try to find a possible crtc which will work */ - for (DrmCrtc *crtc : enc->possible_crtcs()) { - /* We've already tried this earlier */ - if (crtc == enc->crtc()) - continue; - - if (crtc->can_bind(display)) { - crtc->set_display(display); - enc->set_crtc(crtc); - return 0; + if (plane) { + planes_.emplace_back(std::move(plane)); } } - /* We can't use the encoder, but nothing went wrong, try another one */ - return -EAGAIN; -} - -int DrmDevice::CreateDisplayPipe(DrmConnector *connector) { - int display = connector->display(); - /* Try to use current setup first */ - if (connector->encoder()) { - int ret = TryEncoderForDisplay(display, connector->encoder()); - if (!ret) { - return 0; - } - - if (ret != -EAGAIN) { - ALOGE("Could not set mode %d/%d", display, ret); - return ret; - } - } - - for (DrmEncoder *enc : connector->possible_encoders()) { - int ret = TryEncoderForDisplay(display, enc); - if (!ret) { - connector->set_encoder(enc); - return 0; - } - - if (ret != -EAGAIN) { - ALOGE("Could not set mode %d/%d", display, ret); - return ret; - } - } - ALOGE("Could not find a suitable encoder/crtc for display %d", - connector->display()); - return -ENODEV; + return 0; } auto DrmDevice::RegisterUserPropertyBlob(void *data, size_t length) const -> DrmModeUserPropertyBlobUnique { struct drm_mode_create_blob create_blob {}; create_blob.length = length; + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-cstyle-cast) create_blob.data = (__u64)data; - int ret = drmIoctl(fd(), DRM_IOCTL_MODE_CREATEPROPBLOB, &create_blob); - if (ret) { + int ret = drmIoctl(GetFd(), DRM_IOCTL_MODE_CREATEPROPBLOB, &create_blob); + if (ret != 0) { ALOGE("Failed to create mode property blob %d", ret); return {}; } @@ -437,7 +155,8 @@ auto DrmDevice::RegisterUserPropertyBlob(void *data, size_t length) const new uint32_t(create_blob.blob_id), [this](const uint32_t *it) { struct drm_mode_destroy_blob destroy_blob {}; destroy_blob.blob_id = (__u32)*it; - int err = drmIoctl(fd(), DRM_IOCTL_MODE_DESTROYPROPBLOB, &destroy_blob); + int err = drmIoctl(GetFd(), DRM_IOCTL_MODE_DESTROYPROPBLOB, + &destroy_blob); if (err != 0) { ALOGE("Failed to destroy mode property blob %" PRIu32 "/%d", *it, err); @@ -451,16 +170,18 @@ int DrmDevice::GetProperty(uint32_t obj_id, uint32_t obj_type, const char *prop_name, DrmProperty *property) const { drmModeObjectPropertiesPtr props = nullptr; - props = drmModeObjectGetProperties(fd(), obj_id, obj_type); - if (!props) { + props = drmModeObjectGetProperties(GetFd(), obj_id, obj_type); + if (props == nullptr) { ALOGE("Failed to get properties for %d/%x", obj_id, obj_type); return -ENODEV; } bool found = false; for (int i = 0; !found && (size_t)i < props->count_props; ++i) { - drmModePropertyPtr p = drmModeGetProperty(fd(), props->props[i]); - if (!strcmp(p->name, prop_name)) { + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) + drmModePropertyPtr p = drmModeGetProperty(GetFd(), props->props[i]); + if (strcmp(p->name, prop_name) == 0) { + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) property->Init(obj_id, p, props->prop_values[i]); found = true; } @@ -471,22 +192,10 @@ int DrmDevice::GetProperty(uint32_t obj_id, uint32_t obj_type, return found ? 0 : -ENOENT; } -int DrmDevice::GetCrtcProperty(const DrmCrtc &crtc, const char *prop_name, - DrmProperty *property) const { - return GetProperty(crtc.id(), DRM_MODE_OBJECT_CRTC, prop_name, property); -} - -int DrmDevice::GetConnectorProperty(const DrmConnector &connector, - const char *prop_name, - DrmProperty *property) const { - return GetProperty(connector.id(), DRM_MODE_OBJECT_CONNECTOR, prop_name, - property); -} - std::string DrmDevice::GetName() const { - auto *ver = drmGetVersion(fd()); - if (!ver) { - ALOGW("Failed to get drm version for fd=%d", fd()); + auto *ver = drmGetVersion(GetFd()); + if (ver == nullptr) { + ALOGW("Failed to get drm version for fd=%d", GetFd()); return "generic"; } @@ -512,4 +221,22 @@ auto DrmDevice::IsKMSDev(const char *path) -> bool { return is_kms; } +auto DrmDevice::GetConnectors() + -> const std::vector<std::unique_ptr<DrmConnector>> & { + return connectors_; +} + +auto DrmDevice::GetPlanes() -> const std::vector<std::unique_ptr<DrmPlane>> & { + return planes_; +} + +auto DrmDevice::GetCrtcs() -> const std::vector<std::unique_ptr<DrmCrtc>> & { + return crtcs_; +} + +auto DrmDevice::GetEncoders() + -> const std::vector<std::unique_ptr<DrmEncoder>> & { + return encoders_; +} + } // namespace android |