/* * 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 #include #include #include #include #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(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 * 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(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 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 fb, uint32_t zorder, int blankOp) { std::lock_guard lock(mMutex); bool bUpdate = false; bool bBlank = blankOp == UNBLANK ? false : true; drmModeAtomicReqPtr req = nullptr; std::shared_ptr fbdrm = std::static_pointer_cast(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 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(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 infence = std::make_shared(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> emptyCache; std::swap(mBoCache, emptyCache); if (mDrmBo) mDrmBo.reset(); } void DrmVideoPlane::setFlipUserData(void *data) { mUserData = data; mFlipEnable = !!(mUserData != NULL); }