Permalink
Cannot retrieve contributors at this time
Join GitHub today
GitHub is home to over 50 million developers working together to host and review code, manage projects, and build software together.
Sign upxbmc/xbmc/windowing/gbm/DRMAtomic.cpp
Go to file| /* | |
| * Copyright (C) 2005-2018 Team Kodi | |
| * This file is part of Kodi - https://kodi.tv | |
| * | |
| * SPDX-License-Identifier: GPL-2.0-or-later | |
| * See LICENSES/README.md for more information. | |
| */ | |
| #include "DRMAtomic.h" | |
| #include "ServiceBroker.h" | |
| #include "guilib/GUIComponent.h" | |
| #include "guilib/GUIWindowManager.h" | |
| #include "settings/Settings.h" | |
| #include "utils/log.h" | |
| #include <errno.h> | |
| #include <string.h> | |
| #include <drm_fourcc.h> | |
| #include <drm_mode.h> | |
| #include <unistd.h> | |
| using namespace KODI::WINDOWING::GBM; | |
| void CDRMAtomic::DrmAtomicCommit(int fb_id, int flags, bool rendered, bool videoLayer) | |
| { | |
| uint32_t blob_id; | |
| if (flags & DRM_MODE_ATOMIC_ALLOW_MODESET) | |
| { | |
| if (!AddProperty(m_connector, "CRTC_ID", m_crtc->crtc->crtc_id)) | |
| { | |
| return; | |
| } | |
| if (drmModeCreatePropertyBlob(m_fd, m_mode, sizeof(*m_mode), &blob_id) != 0) | |
| { | |
| return; | |
| } | |
| if (m_active && m_orig_crtc && m_orig_crtc->crtc->crtc_id != m_crtc->crtc->crtc_id) | |
| { | |
| // if using a different CRTC than the original, disable original to avoid EINVAL | |
| if (!AddProperty(m_orig_crtc, "MODE_ID", 0)) | |
| { | |
| return; | |
| } | |
| if (!AddProperty(m_orig_crtc, "ACTIVE", 0)) | |
| { | |
| return; | |
| } | |
| } | |
| if (!AddProperty(m_crtc, "MODE_ID", blob_id)) | |
| { | |
| return; | |
| } | |
| if (!AddProperty(m_crtc, "ACTIVE", m_active ? 1 : 0)) | |
| { | |
| return; | |
| } | |
| } | |
| if (rendered) | |
| { | |
| AddProperty(m_gui_plane, "FB_ID", fb_id); | |
| AddProperty(m_gui_plane, "CRTC_ID", m_crtc->crtc->crtc_id); | |
| AddProperty(m_gui_plane, "SRC_X", 0); | |
| AddProperty(m_gui_plane, "SRC_Y", 0); | |
| AddProperty(m_gui_plane, "SRC_W", m_width << 16); | |
| AddProperty(m_gui_plane, "SRC_H", m_height << 16); | |
| AddProperty(m_gui_plane, "CRTC_X", 0); | |
| AddProperty(m_gui_plane, "CRTC_Y", 0); | |
| AddProperty(m_gui_plane, "CRTC_W", m_mode->hdisplay); | |
| AddProperty(m_gui_plane, "CRTC_H", m_mode->vdisplay); | |
| } | |
| else if (videoLayer && !CServiceBroker::GetGUI()->GetWindowManager().HasVisibleControls()) | |
| { | |
| // disable gui plane when video layer is active and gui has no visible controls | |
| AddProperty(m_gui_plane, "FB_ID", 0); | |
| AddProperty(m_gui_plane, "CRTC_ID", 0); | |
| } | |
| auto ret = drmModeAtomicCommit(m_fd, m_req, flags | DRM_MODE_ATOMIC_TEST_ONLY, nullptr); | |
| if (ret < 0) | |
| { | |
| CLog::Log(LOGERROR, "CDRMAtomic::%s - test commit failed: %s", __FUNCTION__, strerror(errno)); | |
| } | |
| else if (ret == 0) | |
| { | |
| ret = drmModeAtomicCommit(m_fd, m_req, flags, nullptr); | |
| if (ret < 0) | |
| { | |
| CLog::Log(LOGERROR, "CDRMAtomic::%s - atomic commit failed: %s", __FUNCTION__, strerror(errno)); | |
| } | |
| } | |
| if (flags & DRM_MODE_ATOMIC_ALLOW_MODESET) | |
| { | |
| if (drmModeDestroyPropertyBlob(m_fd, blob_id) != 0) | |
| CLog::Log(LOGERROR, "CDRMAtomic::%s - failed to destroy property blob: %s", __FUNCTION__, strerror(errno)); | |
| } | |
| drmModeAtomicFree(m_req); | |
| m_req = drmModeAtomicAlloc(); | |
| } | |
| void CDRMAtomic::FlipPage(struct gbm_bo *bo, bool rendered, bool videoLayer) | |
| { | |
| struct drm_fb *drm_fb = nullptr; | |
| if (rendered) | |
| { | |
| if (videoLayer) | |
| m_gui_plane->SetFormat(CDRMUtils::FourCCWithAlpha(m_gui_plane->GetFormat())); | |
| else | |
| m_gui_plane->SetFormat(CDRMUtils::FourCCWithoutAlpha(m_gui_plane->GetFormat())); | |
| drm_fb = CDRMUtils::DrmFbGetFromBo(bo); | |
| if (!drm_fb) | |
| { | |
| CLog::Log(LOGERROR, "CDRMAtomic::%s - Failed to get a new FBO", __FUNCTION__); | |
| return; | |
| } | |
| } | |
| uint32_t flags = 0; | |
| if (m_need_modeset) | |
| { | |
| flags |= DRM_MODE_ATOMIC_ALLOW_MODESET; | |
| m_need_modeset = false; | |
| CLog::Log(LOGDEBUG, "CDRMAtomic::%s - Execute modeset at next commit", __FUNCTION__); | |
| } | |
| DrmAtomicCommit(!drm_fb ? 0 : drm_fb->fb_id, flags, rendered, videoLayer); | |
| } | |
| bool CDRMAtomic::InitDrm() | |
| { | |
| if (!CDRMUtils::OpenDrm(true)) | |
| { | |
| return false; | |
| } | |
| auto ret = drmSetClientCap(m_fd, DRM_CLIENT_CAP_ATOMIC, 1); | |
| if (ret) | |
| { | |
| CLog::Log(LOGERROR, "CDRMAtomic::%s - no atomic modesetting support: %s", __FUNCTION__, strerror(errno)); | |
| return false; | |
| } | |
| m_req = drmModeAtomicAlloc(); | |
| if (!CDRMUtils::InitDrm()) | |
| { | |
| return false; | |
| } | |
| if (!CDRMAtomic::ResetPlanes()) | |
| { | |
| CLog::Log(LOGDEBUG, "CDRMAtomic::%s - failed to reset planes", __FUNCTION__); | |
| } | |
| CLog::Log(LOGDEBUG, "CDRMAtomic::%s - initialized atomic DRM", __FUNCTION__); | |
| return true; | |
| } | |
| void CDRMAtomic::DestroyDrm() | |
| { | |
| CDRMUtils::DestroyDrm(); | |
| drmModeAtomicFree(m_req); | |
| m_req = nullptr; | |
| } | |
| bool CDRMAtomic::SetVideoMode(const RESOLUTION_INFO& res, struct gbm_bo *bo) | |
| { | |
| m_need_modeset = true; | |
| return true; | |
| } | |
| bool CDRMAtomic::SetActive(bool active) | |
| { | |
| m_need_modeset = true; | |
| m_active = active; | |
| return true; | |
| } | |
| bool CDRMAtomic::AddProperty(struct drm_object *object, const char *name, uint64_t value) | |
| { | |
| uint32_t property_id = this->GetPropertyId(object, name); | |
| if (!property_id) | |
| return false; | |
| if (drmModeAtomicAddProperty(m_req, object->id, property_id, value) < 0) | |
| { | |
| CLog::Log(LOGERROR, "CDRMAtomic::%s - could not add property %s", __FUNCTION__, name); | |
| return false; | |
| } | |
| return true; | |
| } | |
| bool CDRMAtomic::ResetPlanes() | |
| { | |
| drmModePlaneResPtr plane_resources = drmModeGetPlaneResources(m_fd); | |
| if (!plane_resources) | |
| { | |
| CLog::Log(LOGERROR, "CDRMAtomic::%s - drmModeGetPlaneResources failed: %s", __FUNCTION__, strerror(errno)); | |
| return false; | |
| } | |
| for (uint32_t i = 0; i < plane_resources->count_planes; i++) | |
| { | |
| drmModePlanePtr plane = drmModeGetPlane(m_fd, plane_resources->planes[i]); | |
| if (!plane) | |
| continue; | |
| drm_object object; | |
| if (!CDRMUtils::GetProperties(m_fd, plane->plane_id, DRM_MODE_OBJECT_PLANE, &object)) | |
| { | |
| CLog::Log(LOGERROR, "CDRMAtomic::%s - could not get plane %u properties: %s", __FUNCTION__, plane->plane_id, strerror(errno));\ | |
| drmModeFreePlane(plane); | |
| continue; | |
| } | |
| AddProperty(&object, "FB_ID", 0); | |
| AddProperty(&object, "CRTC_ID", 0); | |
| CDRMUtils::FreeProperties(&object); | |
| drmModeFreePlane(plane); | |
| } | |
| drmModeFreePlaneResources(plane_resources); | |
| return true; | |
| } |