* Copyright (c) 2021-2023 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "hdi_drm_composition.h"
#include <cerrno>
#include "hdi_drm_layer.h"
namespace OHOS {
namespace HDI {
namespace DISPLAY {
HdiDrmComposition::HdiDrmComposition(const std::shared_ptr<DrmConnector> &connector,
const std::shared_ptr<DrmCrtc> &crtc,
const std::shared_ptr<DrmDevice> &drmDevice)
: mDrmDevice(drmDevice), mConnector(connector), mCrtc(crtc)
{
DISPLAY_LOGD();
}
int32_t HdiDrmComposition::Init()
{
DISPLAY_LOGD();
mPrimPlanes.clear();
mOverlayPlanes.clear();
mPlanes.clear();
DISPLAY_CHK_RETURN((mCrtc == nullptr), DISPLAY_FAILURE, DISPLAY_LOGE("crtc is null"));
DISPLAY_CHK_RETURN((mConnector == nullptr), DISPLAY_FAILURE, DISPLAY_LOGE("connector is null"));
DISPLAY_CHK_RETURN((mDrmDevice == nullptr), DISPLAY_FAILURE, DISPLAY_LOGE("drmDevice is null"));
mPrimPlanes = mDrmDevice->GetDrmPlane(mCrtc->GetPipe(), DRM_PLANE_TYPE_PRIMARY);
mOverlayPlanes = mDrmDevice->GetDrmPlane(mCrtc->GetPipe(), DRM_PLANE_TYPE_OVERLAY);
mPlanes.insert(mPlanes.end(), mPrimPlanes.begin(), mPrimPlanes.end());
mPlanes.insert(mPlanes.end(), mOverlayPlanes.begin(), mOverlayPlanes.end());
return DISPLAY_SUCCESS;
}
int32_t HdiDrmComposition::SetLayers(std::vector<HdiLayer *> &layers, HdiLayer &clientLayer)
{
DISPLAY_LOGD();
mCompLayers.clear();
mCompLayers.push_back(&clientLayer);
return DISPLAY_SUCCESS;
}
int32_t HdiDrmComposition::SetCrtcProperty(DrmPlane &drmPlane,
drmModeAtomicReqPtr pset,
int32_t bufferW,
int32_t bufferH)
{
int ret;
ret = drmModeAtomicAddProperty(pset, drmPlane.GetId(), drmPlane.GetPropCrtc_xId(), 0);
DISPLAY_LOGD("set the fb planeid %{public}d, GetPropCrtc_xId %{public}d, crop.x %{public}d", drmPlane.GetId(),
drmPlane.GetPropCrtc_xId(), 0);
DISPLAY_CHK_RETURN((ret < 0), DISPLAY_FAILURE, DISPLAY_LOGE("set the fb planeid fialed errno : %{public}d", errno));
ret = drmModeAtomicAddProperty(pset, drmPlane.GetId(), drmPlane.GetPropCrtc_yId(), 0);
DISPLAY_LOGD("set the fb planeid %{public}d, GetPropCrtc_yId %{public}d, crop.y %{public}d", drmPlane.GetId(),
drmPlane.GetPropCrtc_yId(), 0);
DISPLAY_CHK_RETURN((ret < 0), DISPLAY_FAILURE, DISPLAY_LOGE("set the fb planeid fialed errno : %{public}d", errno));
ret = drmModeAtomicAddProperty(pset, drmPlane.GetId(), drmPlane.GetPropCrtc_wId(), bufferW);
DISPLAY_LOGD("set the fb planeid %{public}d, GetPropCrtc_wId %{public}d, crop.w %{public}d", drmPlane.GetId(),
drmPlane.GetPropCrtc_wId(), bufferW);
DISPLAY_CHK_RETURN((ret < 0), DISPLAY_FAILURE, DISPLAY_LOGE("set the fb planeid fialed errno : %{public}d", errno));
ret = drmModeAtomicAddProperty(pset, drmPlane.GetId(), drmPlane.GetPropCrtc_hId(), bufferH);
DISPLAY_LOGD("set the fb planeid %{public}d, GetPropCrtc_hId %{public}d, crop.h %{public}d", drmPlane.GetId(),
drmPlane.GetPropCrtc_xId(), bufferH);
DISPLAY_CHK_RETURN((ret < 0), DISPLAY_FAILURE, DISPLAY_LOGE("set the fb planeid fialed errno : %{public}d", errno));
return DISPLAY_SUCCESS;
}
int32_t HdiDrmComposition::SetSrcProperty(DrmPlane &drmPlane,
drmModeAtomicReqPtr pset,
int32_t bufferW,
int32_t bufferH)
{
int ret;
ret = drmModeAtomicAddProperty(pset, drmPlane.GetId(), drmPlane.GetPropSrc_xId(), 0 << 16);
DISPLAY_LOGD("set the fb planeid %{public}d, GetPropSrc_xId %{public}d, displayRect.x %{public}d",
drmPlane.GetId(), drmPlane.GetPropSrc_xId(), 0);
DISPLAY_CHK_RETURN((ret < 0), DISPLAY_FAILURE, DISPLAY_LOGE("set the fb planeid fialed errno : %{public}d", errno));
ret = drmModeAtomicAddProperty(pset, drmPlane.GetId(), drmPlane.GetPropSrc_yId(), 0 << 16);
DISPLAY_LOGD("set the fb planeid %{public}d, GetPropSrc_yId %{public}d, displayRect.y %{public}d",
drmPlane.GetId(), drmPlane.GetPropSrc_yId(), 0);
DISPLAY_CHK_RETURN((ret < 0), DISPLAY_FAILURE, DISPLAY_LOGE("set the fb planeid fialed errno : %{public}d", errno));
ret = drmModeAtomicAddProperty(pset, drmPlane.GetId(), drmPlane.GetPropSrc_wId(),
bufferW << 16);
DISPLAY_LOGD("set the fb planeid %{public}d, GetPropCrtc_wId %{public}d, displayRect.w %{public}d",
drmPlane.GetId(), drmPlane.GetPropSrc_wId(), bufferW);
DISPLAY_CHK_RETURN((ret < 0), DISPLAY_FAILURE, DISPLAY_LOGE("set the fb planeid fialed errno : %{public}d", errno));
ret = drmModeAtomicAddProperty(pset, drmPlane.GetId(), drmPlane.GetPropSrc_hId(),
bufferH << 16);
DISPLAY_LOGD("set the fb planeid %{public}d, GetPropSrc_hId %{public}d, displayRect.h %{public}d",
drmPlane.GetId(), drmPlane.GetPropSrc_hId(), bufferH);
DISPLAY_CHK_RETURN((ret < 0), DISPLAY_FAILURE, DISPLAY_LOGE("set the fb planeid fialed errno : %{public}d", errno));
return DISPLAY_SUCCESS;
}
int32_t HdiDrmComposition::ApplyPlane(HdiDrmLayer &layer,
HdiLayer &hlayer,
DrmPlane &drmPlane,
drmModeAtomicReqPtr pset)
{
int ret;
int fenceFd = layer.GetAcquireFenceFd();
int propId = drmPlane.GetPropFenceInId();
HdiLayerBuffer *layerBuffer = hlayer.GetCurrentBuffer();
int32_t bufferW = layerBuffer->GetWight();
int32_t bufferH = layerBuffer->GetHeight();
DISPLAY_LOGD();
if (propId != 0) {
DISPLAY_LOGD("set the fence in prop");
if (fenceFd >= 0) {
ret = drmModeAtomicAddProperty(pset, drmPlane.GetId(), propId, fenceFd);
DISPLAY_LOGD("set the IfenceProp plane id %{public}d, propId %{public}d, fenceFd %{public}d",
drmPlane.GetId(), propId, fenceFd);
DISPLAY_CHK_RETURN((ret < 0), DISPLAY_FAILURE, DISPLAY_LOGE("set IN_FENCE_FD failed"));
}
}
ret = SetCrtcProperty(drmPlane, pset, bufferW, bufferH);
DISPLAY_CHK_RETURN((ret < 0), DISPLAY_FAILURE, DISPLAY_LOGE("set Crtc fialed errno : %{public}d", errno));
ret = SetSrcProperty(drmPlane, pset, bufferW, bufferH);
DISPLAY_CHK_RETURN((ret < 0), DISPLAY_FAILURE, DISPLAY_LOGE("set Src fialed errno : %{public}d", errno));
ret = drmModeAtomicAddProperty(pset, drmPlane.GetId(), drmPlane.GetPropZposId(), layer.GetZorder());
DISPLAY_LOGD("set the fb planeid %{public}d, GetPropZposId %{public}d, zpos %{public}d",
drmPlane.GetId(), drmPlane.GetPropZposId(), layer.GetZorder());
DISPLAY_CHK_RETURN((ret < 0), DISPLAY_FAILURE, DISPLAY_LOGE("set the zpos fialed errno : %{public}d", errno));
DrmGemBuffer *gemBuffer = layer.GetGemBuffer();
DISPLAY_CHK_RETURN((gemBuffer == nullptr), DISPLAY_FAILURE, DISPLAY_LOGE("current gemBuffer is nullptr"));
DISPLAY_CHK_RETURN((!gemBuffer->IsValid()), DISPLAY_FAILURE, DISPLAY_LOGE("the DrmGemBuffer is invalid"));
ret = drmModeAtomicAddProperty(pset, drmPlane.GetId(), drmPlane.GetPropFbId(), gemBuffer->GetFbId());
DISPLAY_LOGD("set the fb planeid %{public}d, propId %{public}d, fbId %{public}d",
drmPlane.GetId(), drmPlane.GetPropFbId(), gemBuffer->GetFbId());
DISPLAY_CHK_RETURN((ret < 0), DISPLAY_FAILURE, DISPLAY_LOGE("set fb id fialed errno : %{public}d", errno));
ret = drmModeAtomicAddProperty(pset, drmPlane.GetId(), drmPlane.GetPropCrtcId(), mCrtc->GetId());
DISPLAY_LOGD("set the crtc planeId %{public}d, propId %{public}d, crtcId %{public}d",
drmPlane.GetId(), drmPlane.GetPropCrtcId(), mCrtc->GetId());
DISPLAY_CHK_RETURN((ret < 0), DISPLAY_FAILURE, DISPLAY_LOGE("set crtc id fialed errno : %{public}d", errno));
return DISPLAY_SUCCESS;
}
int32_t HdiDrmComposition::UpdateMode(std::unique_ptr<DrmModeBlock> &modeBlock)
{
DISPLAY_LOGD();
if (mCrtc->NeedModeSet()) {
int drmFd = mDrmDevice->GetDrmFd();
drmModeAtomicReqPtr pset = drmModeAtomicAlloc();
modeBlock = mConnector->GetModeBlockFromId(mCrtc->GetActiveModeId());
if ((modeBlock != nullptr) && (modeBlock->GetBlockId() != DRM_INVALID_ID)) {
DISPLAY_LOGD("set crtc to active");
int ret = drmModeAtomicAddProperty(pset, mCrtc->GetId(), mCrtc->GetActivePropId(), 1);
DISPLAY_CHK_RETURN((ret < 0), DISPLAY_FAILURE,
DISPLAY_LOGE("can not add the active prop errno %{public}d", errno));
DISPLAY_LOGD("set the mode");
ret = drmModeAtomicAddProperty(pset, mCrtc->GetId(), mCrtc->GetModePropId(), modeBlock->GetBlockId());
DISPLAY_LOGD("set the mode planeId %{public}d, propId %{public}d, GetBlockId: %{public}d",
mCrtc->GetId(), mCrtc->GetModePropId(), modeBlock->GetBlockId());
DISPLAY_CHK_RETURN((ret < 0), DISPLAY_FAILURE,
DISPLAY_LOGE("can not add the mode prop errno %{public}d", errno));
ret = drmModeAtomicAddProperty(pset, mConnector->GetId(), mConnector->GetPropCrtcId(), mCrtc->GetId());
DISPLAY_LOGD("set the connector id: %{public}d, propId %{public}d, crtcId %{public}d",
mConnector->GetId(), mConnector->GetPropCrtcId(), mCrtc->GetId());
DISPLAY_CHK_RETURN((ret < 0), DISPLAY_FAILURE,
DISPLAY_LOGE("can not add the crtc id prop %{public}d", errno));
uint32_t flags = DRM_MODE_ATOMIC_ALLOW_MODESET;
ret = drmModeAtomicCommit(drmFd, pset, flags, nullptr);
DISPLAY_CHK_RETURN((ret != 0), DISPLAY_FAILURE,
DISPLAY_LOGE("drmModeAtomicCommit failed %{public}d errno %{public}d", ret, errno));
mCrtc->ClearModeSet();
}
}
return DISPLAY_SUCCESS;
}
int32_t HdiDrmComposition::RemoveUnusePlane(drmModeAtomicReqPtr pset)
{
int ret = 0;
for (uint32_t j = 0; j < mPlanes.size(); j++) {
auto &drmPlane = mPlanes[j];
if ((static_cast<int>(drmPlane->GetWinType()) & mCrtc->GetPlaneMask()) && drmPlane->GetPipe() == 0) {
DISPLAY_LOGD("no used plane %{public}s id %{public}d", drmPlane->GetName().c_str(), drmPlane->GetId());
ret = drmModeAtomicAddProperty(pset, drmPlane->GetId(), drmPlane->GetPropFbId(), 0);
ret = drmModeAtomicAddProperty(pset, drmPlane->GetId(), drmPlane->GetPropFbId(), 0);
drmPlane->UnBindPipe();
}
}
return DISPLAY_SUCCESS;
}
int32_t HdiDrmComposition::FindPlaneAndApply(drmModeAtomicReqPtr pset)
{
int32_t ret = 0;
for (uint32_t i = 0; i < mCompLayers.size(); i++) {
HdiDrmLayer *layer = static_cast<HdiDrmLayer *>(mCompLayers[i]);
HdiLayer *hlayer = mCompLayers[i];
for (uint32_t j = 0; j < mPlanes.size(); j++) {
auto &drmPlane = mPlanes[j];
if (drmPlane->GetPipe() != 0 && drmPlane->GetPipe() != (1 << mCrtc->GetPipe())) {
DISPLAY_LOGD("plane %{public}d used pipe %{public}d crtc pipe %{public}d", drmPlane->GetId(),
drmPlane->GetPipe(), mCrtc->GetPipe());
continue;
}
if (!(static_cast<int>(drmPlane->GetWinType()) & mCrtc->GetPlaneMask())) {
continue;
}
DISPLAY_LOGD("use plane %{public}d WinType %{public}x crtc %{public}d PlaneMask %{public}x",
drmPlane->GetId(), drmPlane->GetWinType(), mCrtc->GetId(), mCrtc->GetPlaneMask());
if (drmPlane->GetCrtcId() == mCrtc->GetId() || drmPlane->GetCrtcId() == 0) {
ret = ApplyPlane(*layer, *hlayer, *drmPlane, pset);
DISPLAY_CHK_RETURN((ret != DISPLAY_SUCCESS), ret, DISPLAY_LOGE("apply plane failed"));
drmPlane->BindToPipe(1 << mCrtc->GetPipe());
break;
}
}
}
return DISPLAY_SUCCESS;
}
int32_t HdiDrmComposition::Apply(bool modeSet)
{
uint64_t crtcOutFence = -1;
int ret = 0;
std::unique_ptr<DrmModeBlock> modeBlock;
int drmFd = mDrmDevice->GetDrmFd();
ret = UpdateMode(modeBlock);
DISPLAY_CHK_RETURN((ret != DISPLAY_SUCCESS), DISPLAY_FAILURE, DISPLAY_LOGE("update mode failed"));
DISPLAY_LOGD("mPlane size: %{public}zd mCompLayers size: %{public}zd", mPlanes.size(), mCompLayers.size());
DISPLAY_CHK_RETURN((mPlanes.size() < mCompLayers.size()), DISPLAY_FAILURE, DISPLAY_LOGE("plane not enough"));
drmModeAtomicReqPtr pset = drmModeAtomicAlloc();
DISPLAY_CHK_RETURN((pset == nullptr), DISPLAY_NULL_PTR,
DISPLAY_LOGE("drm atomic alloc failed errno %{public}d", errno));
AtomicReqPtr atomicReqPtr = AtomicReqPtr(pset);
ret = drmModeAtomicAddProperty(atomicReqPtr.Get(), mCrtc->GetId(), mCrtc->GetOutFencePropId(),
(uint64_t)&crtcOutFence);
DISPLAY_LOGD("Apply Set OutFence crtc id: %{public}d, fencePropId %{public}d", mCrtc->GetId(),
mCrtc->GetOutFencePropId());
DISPLAY_CHK_RETURN((ret < 0), DISPLAY_FAILURE, DISPLAY_LOGE("set the outfence property of crtc failed "));
DISPLAY_LOGD("mCompLayers size %{public}zd", mCompLayers.size());
DISPLAY_LOGD("crtc id %{public}d connect id %{public}d encoder id %{public}d", mCrtc->GetId(),
mConnector->GetId(), mConnector->GetEncoderId());
FindPlaneAndApply(atomicReqPtr.Get());
RemoveUnusePlane(atomicReqPtr.Get());
ret = drmModeAtomicAddProperty(pset, mConnector->GetId(), mConnector->GetPropCrtcId(), mCrtc->GetId());
DISPLAY_LOGD("set the connector id: %{public}d, propId %{public}d, crtcId %{public}d", mConnector->GetId(),
mConnector->GetPropCrtcId(), mCrtc->GetId());
DISPLAY_CHK_RETURN((ret < 0), DISPLAY_FAILURE,
DISPLAY_LOGE("can not add the crtc id prop %{public}d", errno));
DISPLAY_LOGD("set crtc to active");
ret = drmModeAtomicAddProperty(pset, mCrtc->GetId(), mCrtc->GetActivePropId(), 1);
DISPLAY_CHK_RETURN((ret < 0), DISPLAY_FAILURE,
DISPLAY_LOGE("can not add the active prop errno %{public}d", errno));
uint32_t flags = DRM_MODE_ATOMIC_NONBLOCK;
ret = drmModeAtomicCommit(drmFd, atomicReqPtr.Get(), flags, nullptr);
DISPLAY_CHK_RETURN((ret != 0), DISPLAY_FAILURE,
DISPLAY_LOGE("drmModeAtomicCommit failed %{public}d errno %{public}d", ret, errno));
for (auto layer : mCompLayers) {
layer->SetReleaseFence(static_cast<int>(crtcOutFence));
}
return DISPLAY_SUCCESS;
}
}
}
}