394 lines
12 KiB
C++
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);
|
|
}
|