diff --git a/services/ui/drm_driver.cpp b/services/ui/drm_driver.cpp index 201194285e7d56c9082279c560c4401804c1a9d7..44a5ae01564202329db835ce8b07bca6494b003b 100644 --- a/services/ui/drm_driver.cpp +++ b/services/ui/drm_driver.cpp @@ -72,32 +72,204 @@ int DrmDriver::ModesetCreateFb(struct BufferObject *bo) return 0; } +drmModeCrtc *DrmDriver::GetCrtc(const drmModeRes &res, const int fd, const drmModeConnector &conn) const +{ + // if connector has one encoder, use it + drmModeEncoder *encoder = nullptr; + if (conn.encoder_id != 0) { + encoder = drmModeGetEncoder(fd, conn.encoder_id); + } + if (encoder != nullptr && encoder->crtc_id != 0) { + uint32_t crtcId = encoder->crtc_id; + drmModeFreeEncoder(encoder); + return drmModeGetCrtc(fd, crtcId); + } + + if (encoder != nullptr) { + drmModeFreeEncoder(encoder); + } + + // try get a vaild encoder and crtc + for (int i = 0; i < conn.count_encoders; i++) { + encoder = drmModeGetEncoder(fd, conn.encoders[i]); + if (encoder == nullptr) { + continue; + } + + for (int j = 0; j < res.count_crtcs; j++) { + if ((encoder->possible_crtcs & (1u << static_cast(j))) != 0) { + drmModeFreeEncoder(encoder); + return drmModeGetCrtc(fd, res.crtcs[j]); + } + } + drmModeFreeEncoder(encoder); + } + return nullptr; +} + +drmModeConnector *DrmDriver::GetFirstConnector(const drmModeRes &res, const int fd) const +{ + // get connected connector + for (int i = 0; i < res.count_connectors; i++) { + drmModeConnector *conn = drmModeGetConnector(fd, res.connectors[i]); + if (conn == nullptr) { + continue; + } + if (conn->count_modes > 0 && + conn->connection == DRM_MODE_CONNECTED) { + return conn; + } + drmModeFreeConnector(conn); + } + return nullptr; +} + +drmModeConnector *DrmDriver::GetConnectorByType(const drmModeRes &res, const int fd, const uint32_t type) const +{ + // get connected connector + for (int i = 0; i < res.count_connectors; i++) { + drmModeConnector *conn = drmModeGetConnector(fd, res.connectors[i]); + if (conn == nullptr) { + continue; + } + if (conn->connector_type == type && + conn->count_modes > 0 && + conn->connection == DRM_MODE_CONNECTED) { + return conn; + } + drmModeFreeConnector(conn); + } + return nullptr; +} + + +drmModeConnector *DrmDriver::GetConnector(const drmModeRes &res, const int fd, uint32_t &modeId) const +{ + // get main connector : lvds edp and dsi + uint32_t mainConnector[] = { + DRM_MODE_CONNECTOR_LVDS, + DRM_MODE_CONNECTOR_eDP, + DRM_MODE_CONNECTOR_DSI, + }; + + drmModeConnector *conn = nullptr; + for (uint32_t i = 0; i < sizeof(mainConnector) / sizeof(mainConnector[0]); i++) { + conn = GetConnectorByType(res, fd, mainConnector[i]); + if (conn != nullptr) { + break; + } + } + + if (conn == nullptr) { + conn = GetFirstConnector(res, fd); + } + + if (conn == nullptr) { + LOG(ERROR) << "DrmDriver cannot get vaild connector"; + return nullptr; + } + + // get preferred mode index + modeId = 0; + for (int i = 0; i < conn->count_modes; i++) { + if ((conn->modes[i].type & DRM_MODE_TYPE_PREFERRED) != 0) { + modeId = i; + break; + } + } + + return conn; +} + +drmModeRes *DrmDriver::GetResources(int &fd) const +{ + // 1: open drm resource + drmModeRes *res = nullptr; + for (int i = 0; i < DRM_MAX_MINOR; i++) { + res = GetOneResources(i, fd); + if (res != nullptr) { + break; + } + } + return res; +} + +drmModeRes *DrmDriver::GetOneResources(const int devIndex, int &fd) const +{ + // 1: open drm device + fd = -1; + std::string devName = std::string("/dev/dri/card") + std::to_string(devIndex); + int tmpFd = open(devName.c_str(), O_RDWR | O_CLOEXEC); + if (tmpFd < 0) { + LOG(ERROR) << "open failed " << devName; + return nullptr; + } + // 2: check drm capacity + uint64_t cap = 0; + int ret = drmGetCap(tmpFd, DRM_CAP_DUMB_BUFFER, &cap); + if (ret != 0 || cap == 0) { + LOG(ERROR) << "drmGetCap failed"; + close(tmpFd); + return nullptr; + } + + // 3: get drm resources + drmModeRes *res = drmModeGetResources(tmpFd); + if (res == nullptr) { + LOG(ERROR) << "drmModeGetResources failed"; + close(tmpFd); + return nullptr; + } + + // 4: check it has connected connector and crtc + if (res->count_crtcs > 0 && res->count_connectors > 0 && res->count_encoders > 0) { + drmModeConnector *conn = GetFirstConnector(*res, tmpFd); + if (conn != nullptr) { + // don't close fd + LOG(INFO) << "drm dev:" << devName; + drmModeFreeConnector(conn); + fd = tmpFd; + return res; + } + } + close(tmpFd); + drmModeFreeResources(res); + return nullptr; +} + int DrmDriver::DrmInit(void) { - fd_ = open("/dev/dri/card0", O_RDWR | O_CLOEXEC); - if (fd_ < 0) { - LOG(ERROR) << "open failed"; + // 1: open drm resource + res_ = GetResources(fd_); + if (fd_ < 0 || res_ == nullptr) { + LOG(ERROR) << "DrmInit: GetResources failed"; return -1; } - res_ = drmModeGetResources(fd_); - if (res_ == nullptr) { - LOG(ERROR) << "drmModeGetResources"; + // 2 : get connected connector + uint32_t modeId; + conn_ = GetConnector(*res_, fd_, modeId); + if (conn_ == nullptr) { + LOG(ERROR) << "DrmInit: GetConnector failed"; return -1; } - uint32_t crtcId = res_->crtcs[0]; - uint32_t connId = res_->connectors[1]; - conn_ = drmModeGetConnector(fd_, connId); - if (conn_ == nullptr) { - LOG(ERROR) << "drmModeGetConnector"; + // 3: get vaild encoder and crtc + crtc_ = GetCrtc(*res_, fd_, *conn_); + if (crtc_ == nullptr) { + LOG(ERROR) << "DrmInit: GetCrtc failed"; return -1; } - buff_.width = conn_->modes[0].hdisplay; - buff_.height = conn_->modes[0].vdisplay; + // 4: create userspace buffer + buff_.width = conn_->modes[modeId].hdisplay; + buff_.height = conn_->modes[modeId].vdisplay; ModesetCreateFb(&buff_); - drmModeSetCrtc(fd_, crtcId, buff_.fbId, 0, 0, &connId, 1, &conn_->modes[0]); + + // 5: bind ctrc and connector + drmModeSetCrtc(fd_, crtc_->crtc_id, buff_.fbId, 0, 0, &conn_->connector_id, 1, &conn_->modes[modeId]); + LOG(INFO) << "DrmInit: buff_.width:" << buff_.width << " buff_.height:" << buff_.height; + LOG(INFO) << "DrmInit: crtc_id:" << crtc_->crtc_id << " connector_id:" << conn_->connector_id; LOG(INFO) << " drm init success."; return 0; } @@ -111,14 +283,29 @@ void DrmDriver::LoadDrmDriver() void DrmDriver::ModesetDestroyFb(struct BufferObject *bo) { - struct drm_mode_destroy_dumb destroy = {}; - drmModeRmFB(fd_, bo->fbId); - munmap(bo->vaddr, bo->size); - destroy.handle = bo->handle; - drmIoctl(fd_, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy); - drmModeFreeConnector(conn_); - drmModeFreeResources(res_); - close(fd_); + if (fd_ > 0 && bo->fbId != 0) { + drmModeRmFB(fd_, bo->fbId); + } + if (bo->vaddr != nullptr) { + munmap(bo->vaddr, bo->size); + } + if (fd_ > 0) { + struct drm_mode_destroy_dumb destroy = {}; + destroy.handle = bo->handle; + drmIoctl(fd_, DRM_IOCTL_GEM_CLOSE, &destroy); + } + if (crtc_ != nullptr) { + drmModeFreeCrtc(crtc_); + } + if (conn_ != nullptr) { + drmModeFreeConnector(conn_); + } + if (res_ != nullptr) { + drmModeFreeResources(res_); + } + if (fd_ > 0) { + close(fd_); + } } DrmDriver::~DrmDriver() diff --git a/services/ui/drm_driver.h b/services/ui/drm_driver.h index 1e0749293dd69d8e6e3db5bfbcba766313abc6fd..2d10391f3dcb514802ca8eaa623c2b19bf881e6e 100644 --- a/services/ui/drm_driver.h +++ b/services/ui/drm_driver.h @@ -40,7 +40,7 @@ struct BufferObject { class DrmDriver { protected: - DrmDriver() : fd_(-1), conn_(nullptr), res_(nullptr) {} + DrmDriver() : fd_(-1), conn_(nullptr), res_(nullptr), crtc_(nullptr) {} virtual ~DrmDriver(); void FlipBuffer(const void* buf); void LoadDrmDriver(); @@ -48,9 +48,16 @@ private: int ModesetCreateFb(struct BufferObject *bo); void ModesetDestroyFb(struct BufferObject *bo); int DrmInit(); + drmModeCrtc *GetCrtc(const drmModeRes &res, const int fd, const drmModeConnector &conn) const; + drmModeConnector *GetFirstConnector(const drmModeRes &res, const int fd) const; + drmModeConnector *GetConnectorByType(const drmModeRes &res, const int fd, const uint32_t type) const; + drmModeConnector *GetConnector(const drmModeRes &res, const int fd, uint32_t &modeId) const; + drmModeRes *GetResources(int &fd) const; + drmModeRes *GetOneResources(const int devIndex, int &fd) const; int fd_; drmModeConnector *conn_; drmModeRes *res_; + drmModeCrtc *crtc_; struct BufferObject buff_ {}; }; } // namespace updater