Files

394 lines
12 KiB
C++

/*
* Copyright (C) 2024 Amlogic Corporation.
*
* 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 <fcntl.h>
#include <sys/ioctl.h>
#include <cinttypes>
#include <cstring>
#include <unistd.h>
#include "DrmVideoPlane.h"
#include "DrmAsyncCommitor.h"
#include "DispAdptLog.h"
#include "DrmSync.h"
#include "MesonLayer.h"
DrmVideoPlane::DrmVideoPlane(int drmFd, drmModePlanePtr p)
: HwDisplayPlaneBase (drmFd)
{
initialize(p);
mCrtc_Id = 0;
mPrimary = false;
mObserver = nullptr;
}
int32_t DrmVideoPlane::initialize(drmModePlanePtr p)
{
setId(p->plane_id);
setPossibleCrtcs(p->possible_crtcs);
loadProperties();
mDrmBo = std::make_shared<DrmVideoBo>(mDrvFd);
mBlank = p->fb_id > 0 ? false : true;
// parse caps
uint32_t caps = 0;
if (!mZpos->isImmutable()) {
caps |= PLANE_SUPPORT_ZORDER;
}
if (mVideoCap.get()) {
int video_cap = mVideoCap->getValue();
if (video_cap & 0x1000000)
caps |= PLANE_SUPPORT_MOSAIC;
}
setCaps(caps);
if (mMaxFbSize.get()) {
int size = mMaxFbSize->getValue();
mMaxInputFbSizeW = size >> 16;
mMaxInputFbSizeH = size & 0xffff;
}
if (mMinFbSize.get()) {
int size = mMinFbSize->getValue();
mMinInputFbSizeW = size >> 16;
mMinInputFbSizeH = size & 0xffff;
}
std::string name = "DrmVideo-" + std::to_string(mId);
setName(std::move(name));
setType(DRM_VIDEO_PLANE);
return 0;
}
void DrmVideoPlane::loadProperties()
{
struct {
const char * propname;
std::shared_ptr<DrmProperty> * drmprop;
} planeProps[] = {
{DRM_PLANE_PROP_TYPE, &mType},
{DRM_PLANE_PROP_FBID, &mFbId},
{DRM_PLANE_PROP_ASYNC_INFENCE, &mAsyncInFence},
{DRM_PLANE_PROP_SRCX, &mSrcX},
{DRM_PLANE_PROP_SRCY, &mSrcY},
{DRM_PLANE_PROP_SRCW, &mSrcW},
{DRM_PLANE_PROP_SRCH, &mSrcH},
{DRM_PLANE_PROP_CRTCID, &mCrtcId},
{DRM_PLANE_PROP_CRTCX, &mCrtcX},
{DRM_PLANE_PROP_CRTCY, &mCrtcY},
{DRM_PLANE_PROP_CRTCW, &mCrtcW},
{DRM_PLANE_PROP_CRTCH, &mCrtcH},
{DRM_PLANE_PROP_Z, &mZpos},
{DRM_PLANE_PROR_IN_FORMATS, &mInFormats},
{DRM_PLANE_PROP_ALPHA, &mAlpha},
{DRM_PLANE_PROP_VIDEO_MAX_SIZE, &mMaxFbSize},
{DRM_PLANE_PROP_VIDEO_MIN_SIZE, &mMinFbSize},
{DRM_PLANE_PROP_VIDEO_CAP, &mVideoCap},
{DRM_PLANE_PROP_VIDEO_FRAME_FLAG, &mFrameFlag},
{DRM_PLANE_PROP_ROTATION, &mRotate},
};
const int planePropsNum = sizeof(planeProps)/sizeof(planeProps[0]);
int initedProps = 0;
drmModeObjectPropertiesPtr props =
drmModeObjectGetProperties(mDrvFd, mId, DRM_MODE_OBJECT_PLANE);
DISPLAY_ASSERT(props != NULL, "DrmVideoPlane::loadProperties failed.");
for (uint32_t i = 0; i < props->count_props; i++) {
drmModePropertyPtr prop = drmModeGetProperty(mDrvFd, props->props[i]);
for (int j = 0; j < planePropsNum; j++) {
if (strcmp(prop->name, planeProps[j].propname) == 0) {
*(planeProps[j].drmprop) =
std::make_shared<DrmProperty>(mDrvFd, prop, mId, props->prop_values[i]);
initedProps ++;
break;
}
}
drmModeFreeProperty(prop);
}
drmModeFreeObjectProperties(props);
if (initedProps != planePropsNum)
DISPLAY_LOGD("NOT ALL PROPS LOADED, %d-%d.", initedProps, planePropsNum);
for (int i = 0; i < planePropsNum; i++) {
if (!(*(planeProps[i].drmprop)).get())
DISPLAY_LOGD("property %s init failed", planeProps[i].propname);
}
}
int32_t DrmVideoPlane::getFixedZorder()
{
return 0;
}
int32_t DrmVideoPlane::setCrtcId(uint32_t crtcId)
{
mCrtc_Id = crtcId;
return 0;
}
bool DrmVideoPlane::isFbSupport(std::shared_ptr<DrmFramebufferBase> fb)
{
uint32_t width;
uint32_t height;
uint32_t format;
uint32_t stride;
uint32_t alignHeight = 0;
if (fb->mFbType != DRM_FB_VIDEO_UVM_DMA)
return false;
fb->getBufferInfo(width, height, stride, alignHeight, format);
if (width > (uint32_t)mMaxInputFbSizeW || width < (uint32_t)mMinInputFbSizeW)
return false;
if (height > (uint32_t)mMaxInputFbSizeH || width < (uint32_t)mMinInputFbSizeH)
return false;
return true;
}
int32_t DrmVideoPlane::setPlane(
std::shared_ptr<DrmFramebufferBase> fb, uint32_t zorder, int blankOp)
{
std::lock_guard<std::mutex> lock(mMutex);
bool bUpdate = false;
bool bBlank = blankOp == UNBLANK ? false : true;
drmModeAtomicReqPtr req = nullptr;
std::shared_ptr<MesonLayer> fbdrm = std::static_pointer_cast<MesonLayer>(fb);
if (mBlank != bBlank)
DISPLAY_LOGD("DrmVideoPlane::setPlane(%d) %s", mId, bBlank ? "disable" : "enable");
if (bBlank) {
if (!mBlank && !mKeepFrame) {
/* set fbid =0&&crtc=0, driver will check it. */
req = drmModeAtomicAlloc();
DISPLAY_ASSERT(req != NULL, "drm video plane get empty req.");
mFbId->setValue(0);
mFbId->apply(req);
mCrtcId->setValue(0);
mCrtcId->apply(req);
bUpdate = true;
}
} else {
DISPLAY_ASSERT(fb != nullptr, "setPlane fb is nullptr, it is out of the question");
if (mFb == fb && !fb->isFbUpdated()) {
return 0;
}
int bufferFd = fb->getBufferFd();
if (bufferFd < 0) {
DISPLAY_LOGD("setPlane but fb: %" PRIu64 " %p has no buffer", fb->getUniqueId(), fb.get());
fb->setCurReleaseFence(-1);
return 0;
}
int32_t ret = 0;
req = drmModeAtomicAlloc();
DISPLAY_ASSERT(req != NULL, "drm video plane get empty req.");
std::shared_ptr<DrmVideoBo> prevDrmBo = mDrmBo;
if (mDrmBo.get())
prevDrmBo = mDrmBo;
if (mFrameFlag.get()) {
source_type_t source_type;
fb->getBufferFd(source_type);
uint64_t frameFlag = mFrameFlag->getValue();
if (source_type == HWC_CREAT_ION) {
mFrameFlag->setValue(1);
} else {
mFrameFlag->setValue(0);
}
if (frameFlag != mFrameFlag->getValue())
bUpdate = true;
}
mDrmBo = std::make_shared<DrmVideoBo>(mDrvFd);
if ((ret = mDrmBo->import(fb)) != 0) {
DISPLAY_LOGE("DrmVideoBo import failed, return.");
drmModeAtomicFree(req);
return ret;
}
if (prevDrmBo.get() && prevDrmBo->getHandle() == mDrmBo->getHandle())
prevDrmBo->setRepeatBuffer(true);
if (mDrmBo->fbId != mFbId->getValue()) {
mFbId->setValue(mDrmBo->fbId);
bUpdate = true;
}
if (mCrtcId->getValue() != mCrtc_Id) {
mCrtcId->setValue(mCrtc_Id);
bUpdate = true;
}
if (mSrcX->getValue() != (uint64_t)mDrmBo->srcRect.left ||
mSrcY->getValue() != (uint64_t)mDrmBo->srcRect.top ||
mSrcW->getValue() != (uint64_t)(mDrmBo->srcRect.right - mDrmBo->srcRect.left) ||
mSrcH->getValue() != (uint64_t)(mDrmBo->srcRect.bottom - mDrmBo->srcRect.top)) {
mSrcX->setValue(mDrmBo->srcRect.left << 16);
mSrcY->setValue(mDrmBo->srcRect.top << 16);
mSrcW->setValue((mDrmBo->srcRect.right - mDrmBo->srcRect.left) << 16);
mSrcH->setValue((mDrmBo->srcRect.bottom - mDrmBo->srcRect.top) << 16);
bUpdate = true;
}
if (mCrtcX->getValue() != (uint64_t)mDrmBo->crtcRect.left ||
mCrtcY->getValue() != (uint64_t)mDrmBo->crtcRect.top ||
mCrtcW->getValue() != (uint64_t)(mDrmBo->crtcRect.right - mDrmBo->crtcRect.left) ||
mCrtcH->getValue() != (uint64_t)(mDrmBo->crtcRect.bottom - mDrmBo->crtcRect.top)) {
mCrtcX->setValue(mDrmBo->crtcRect.left);
mCrtcY->setValue(mDrmBo->crtcRect.top);
mCrtcW->setValue(mDrmBo->crtcRect.right - mDrmBo->crtcRect.left);
mCrtcH->setValue(mDrmBo->crtcRect.bottom - mDrmBo->crtcRect.top);
bUpdate = true;
}
if (mZpos->getValue() != zorder) {
mZpos->setValue(zorder);
bUpdate = true;
}
if (mRotate.get()) {
uint64_t rotateValue = DRM_MODE_ROTATE_0;
if (mDrmBo->rotate == TRANSFORM_ROT_180) {
rotateValue = DRM_MODE_ROTATE_180;
} else if (mDrmBo->rotate == TRANSFORM_FLIP_H) {
rotateValue = DRM_MODE_ROTATE_0 | DRM_MODE_REFLECT_X;
} else if(mDrmBo->rotate == TRANSFORM_FLIP_V) {
rotateValue = DRM_MODE_ROTATE_0 | DRM_MODE_REFLECT_Y;
} else {
rotateValue = DRM_MODE_ROTATE_0;
}
if (mRotate->getValue() != rotateValue) {
mRotate->setValue(rotateValue);
bUpdate = true;
}
}
if (bUpdate) {
mFbId->apply(req);
mCrtcId->apply(req);
mSrcX->apply(req);
mSrcY->apply(req);
mSrcW->apply(req);
mSrcH->apply(req);
mCrtcX->apply(req);
mCrtcY->apply(req);
mCrtcW->apply(req);
mCrtcH->apply(req);
mZpos->apply(req);
if (mFrameFlag.get())
mFrameFlag->apply(req);
if (mRotate.get())
mRotate->apply(req);
if (mDrmBo->inFence >= 0) {
if (mAsyncInFence.get()) {
mAsyncInFence->setValue(mDrmBo->inFence);
mAsyncInFence->apply(req);
} else {
std::shared_ptr<DrmFence> infence
= std::make_shared<DrmFence>(fb->getAcquireFenceFd());
infence->wait(3000);
}
}
}
}
int outFence = -1;
if (bUpdate) {
uint32_t flag = DRM_MODE_ATOMIC_NONBLOCK;
if (mFlipEnable && !bBlank) {
flag = DRM_MODE_PAGE_FLIP_EVENT;
if (fbdrm.get())
fbdrm->setFlipDataToUserData(mUserData);
}
int ret = drmModeAsyncAtomicCommit(mDrvFd, req, flag, mUserData);
if (ret) {
DISPLAY_LOGE("drm async atomic commit ret (%d)", ret);
} else {
if (mFlipEnable && !bBlank && mObserver != NULL)
mObserver->onPoll();
}
// Async commit video frame and get out fence
if (mDrmBo.get())
outFence = drmGetVideoFence(mDrvFd, mDrmBo->dmaBufFd);
if (mDrmBo.get() && fb.get()) {
DISPLAY_LOGV("DrmVideoPlane(%d) setPlane layerId(%" PRIu64 ") zorder(%d) "
"type(%s) bufferFd(%d) format(%d) dispFrame(%s) srcCrop(%s) "
"inFence(%d) outFence(%d)", mId, fb->mId, fb->mZorder,
drmFbTypeToString(fb->getFbType()),fb->getBufferFd(), mDrmBo->format,
mDrmBo->crtcRect.toString().c_str(), mDrmBo->srcRect.toString().c_str(),
mDrmBo->inFence, outFence);
}
}
if (fb.get()) {
fb->setCurReleaseFence(outFence);
fbdrm->setDiProcessorFd(-1);
} else if (outFence >= 0) {
close(outFence);
}
if (bBlank && mBlank != bBlank) {
mKeepFrame = false;
clearPlaneResources();
}
if (mDrmBo.get()) {
mBoCache.push(mDrmBo);
}
if (mBoCache.size() > 3) {
mBoCache.pop();
}
mBlank = bBlank;
mFb = std::move(fb);
drmModeAtomicFree(req);
return 0;
}
void DrmVideoPlane::clearPlaneResources()
{
/* clear drmVideobo cache */
DISPLAY_LOGV("drm video plane clear drm bo caches");
std::queue<std::shared_ptr<DrmVideoBo>> emptyCache;
std::swap(mBoCache, emptyCache);
if (mDrmBo)
mDrmBo.reset();
}
void DrmVideoPlane::setFlipUserData(void *data)
{
mUserData = data;
mFlipEnable = !!(mUserData != NULL);
}