1064 lines
30 KiB
C++
1064 lines
30 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 <cinttypes>
|
||
|
|
|
||
|
|
#include <drm_fourcc.h>
|
||
|
|
#include <video_tunnel.h>
|
||
|
|
#include <VtInstanceMgr.h>
|
||
|
|
|
||
|
|
#include "MesonDisplay.h"
|
||
|
|
#include "MesonLayer.h"
|
||
|
|
#include "DispAdptLog.h"
|
||
|
|
|
||
|
|
MesonLayer::MesonLayer() : DrmFramebufferBase()
|
||
|
|
{
|
||
|
|
init();
|
||
|
|
mDisplayId = 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
MesonLayer::MesonLayer(uint32_t dispId) : DrmFramebufferBase()
|
||
|
|
{
|
||
|
|
init();
|
||
|
|
mDisplayId = dispId;
|
||
|
|
}
|
||
|
|
|
||
|
|
MesonLayer::~MesonLayer()
|
||
|
|
{
|
||
|
|
if (mFd >= 0) close(mFd);
|
||
|
|
mFd = -1;
|
||
|
|
if (mDifd >= 0) close(mDifd);
|
||
|
|
mDifd = -1;
|
||
|
|
|
||
|
|
if (isVtBuffer()) {
|
||
|
|
releaseVtResource();
|
||
|
|
releaseUvmResourceLock();
|
||
|
|
} else
|
||
|
|
releaseResource();
|
||
|
|
}
|
||
|
|
|
||
|
|
void MesonLayer::init()
|
||
|
|
{
|
||
|
|
mFd = -1;
|
||
|
|
mTunnelFd = -1;
|
||
|
|
mNeedReleaseVtResource = false;
|
||
|
|
mTunnelIdUpdate = false;
|
||
|
|
mVtRefreshed = false;
|
||
|
|
mNeedAskRefresh = false;
|
||
|
|
mVtUpdate = false;
|
||
|
|
mQueuedFrames = 0;
|
||
|
|
mGameMode = false;
|
||
|
|
mVideoDisplayStatus = VT_VIDEO_STATUS_SHOW;
|
||
|
|
mPreUvmBufferFd = -1;
|
||
|
|
mDifd = -1;
|
||
|
|
}
|
||
|
|
|
||
|
|
int32_t MesonLayer::setTunnelId(int tunnelId, std::shared_ptr<VtDisplayObserver> observer)
|
||
|
|
{
|
||
|
|
mTunnelId = tunnelId;
|
||
|
|
|
||
|
|
if (tunnelId >= 128) {
|
||
|
|
setFbType(DRM_FB_VIDEO_UVM_DMA);
|
||
|
|
mTunnelFd = meson_vt_open_by_mode(tunnelId >= 128 ? 0 : 1);
|
||
|
|
meson_vt_connect(mTunnelFd, mTunnelId, 1);
|
||
|
|
if (observer.get())
|
||
|
|
observer.reset();
|
||
|
|
} else if (tunnelId < 128 && tunnelId >= 0) {
|
||
|
|
setFbType(DRM_FB_VIDEO_TUNNEL_SIDEBAND);
|
||
|
|
mNeedReleaseVtResource = true;
|
||
|
|
mVtTransform = 0;
|
||
|
|
VtInstanceMgr::getInstance().lockInstancesMutex();
|
||
|
|
|
||
|
|
if (!mDisplayObserver.get())
|
||
|
|
mDisplayObserver = std::move(observer);
|
||
|
|
|
||
|
|
int ret = registerConsumer();
|
||
|
|
if (ret >= 0) {
|
||
|
|
DISPLAY_LOGD("%s [%" PRId64 "] register consumer for videotunnel %d succeeded",
|
||
|
|
__func__, mId, tunnelId);
|
||
|
|
mQueueItems.clear();
|
||
|
|
mTunnelIdUpdate = true;
|
||
|
|
} else {
|
||
|
|
DISPLAY_LOGE("%s [%" PRId64 "] register consumer for videotunnel %d failed, error %d",
|
||
|
|
__func__, mId, tunnelId, ret);
|
||
|
|
mTunnelId = -1;
|
||
|
|
VtInstanceMgr::getInstance().unlockInstancesMutex();
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
VtInstanceMgr::getInstance().unlockInstancesMutex();
|
||
|
|
}
|
||
|
|
|
||
|
|
/* fbtype is not tunnel sideband */
|
||
|
|
if (mFbType != DRM_FB_VIDEO_TUNNEL_SIDEBAND)
|
||
|
|
releaseUvmResourceLock();
|
||
|
|
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
int32_t MesonLayer::setIndex(int index)
|
||
|
|
{
|
||
|
|
mIndex = index;
|
||
|
|
setVideoPriority(mIndex);
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
int32_t MesonLayer::getIndex()
|
||
|
|
{
|
||
|
|
return mIndex;
|
||
|
|
}
|
||
|
|
|
||
|
|
int32_t MesonLayer::setZorder(uint32_t z)
|
||
|
|
{
|
||
|
|
mCurrZorder = z;
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
int32_t MesonLayer::getCurZorder()
|
||
|
|
{
|
||
|
|
return mCurrZorder;
|
||
|
|
}
|
||
|
|
|
||
|
|
void MesonLayer::updateZorder()
|
||
|
|
{
|
||
|
|
DrmFramebufferBase::setZorder(mCurrZorder);
|
||
|
|
}
|
||
|
|
|
||
|
|
int32_t MesonLayer::setDisplayFrame(drm_rect_t dispFrame)
|
||
|
|
{
|
||
|
|
if (dispFrame.left <= 0 && dispFrame.top <= 0)
|
||
|
|
setVideoPriority(0);
|
||
|
|
else
|
||
|
|
setVideoPriority(mIndex);
|
||
|
|
return DrmFramebufferBase::setDisplayFrame(dispFrame);
|
||
|
|
}
|
||
|
|
|
||
|
|
int32_t MesonLayer::setCurReleaseFence(int32_t fenceFd)
|
||
|
|
{
|
||
|
|
mCurReleaseFence.reset(new DrmFence(fenceFd));
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
int32_t MesonLayer::getCurReleaseFence()
|
||
|
|
{
|
||
|
|
return (mCurReleaseFence.get() ? mCurReleaseFence->dup() : -1);
|
||
|
|
}
|
||
|
|
|
||
|
|
int32_t MesonLayer::setProcessFence(int32_t fenceFd) {
|
||
|
|
mProcessFence.reset(new DrmFence(fenceFd));
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
int32_t MesonLayer::getProcessFence() {
|
||
|
|
return (mProcessFence.get() ? mProcessFence->dup() : -1);
|
||
|
|
}
|
||
|
|
|
||
|
|
int32_t MesonLayer::onLayerDisplayed(int32_t releaseFence,
|
||
|
|
int32_t processFence) {
|
||
|
|
if (releaseFence < 0 || processFence < 0) {
|
||
|
|
int32_t fenceFd = (releaseFence < 0) ? processFence : releaseFence;
|
||
|
|
mCurReleaseFence.reset(new DrmFence(fenceFd));
|
||
|
|
} else {
|
||
|
|
mCurReleaseFence = DrmFence::merge(
|
||
|
|
"FBProcessor",
|
||
|
|
std::make_shared<DrmFence>(releaseFence),
|
||
|
|
std::make_shared<DrmFence>(processFence));
|
||
|
|
}
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
void MesonLayer::setPresentTime(nsecs_t expectedPresentTime)
|
||
|
|
{
|
||
|
|
std::lock_guard<std::mutex> lock(mMutex);
|
||
|
|
|
||
|
|
nsecs_t previousExpectedTime;
|
||
|
|
previousExpectedTime = ((mExpectedPresentTime == 0) ?
|
||
|
|
ns2us(expectedPresentTime) : mExpectedPresentTime);
|
||
|
|
|
||
|
|
mExpectedPresentTime = ns2us(expectedPresentTime);
|
||
|
|
|
||
|
|
DISPLAY_LOGV("[%s] [%d] [%" PRIu64 "] vsyncTimeStamp:%" PRId64 ", diffExpected:%" PRId64,
|
||
|
|
__func__, mDisplayId, mId, mExpectedPresentTime, mExpectedPresentTime - previousExpectedTime);
|
||
|
|
}
|
||
|
|
|
||
|
|
bool MesonLayer::isVtBuffer()
|
||
|
|
{
|
||
|
|
return mFbType == DRM_FB_VIDEO_TUNNEL_SIDEBAND;
|
||
|
|
}
|
||
|
|
|
||
|
|
bool MesonLayer::isFbUpdated()
|
||
|
|
{
|
||
|
|
std::lock_guard<std::mutex> lock(mMutex);
|
||
|
|
|
||
|
|
if (isVtBuffer())
|
||
|
|
return (shouldPresentNow(mCurBufferItem) && mVtUpdate) || mVtRefreshed;
|
||
|
|
return mUpdated;
|
||
|
|
}
|
||
|
|
|
||
|
|
bool MesonLayer::shouldPresentNow(const std::shared_ptr<BufferItem> item)
|
||
|
|
{
|
||
|
|
if (!item.get())
|
||
|
|
return false;
|
||
|
|
|
||
|
|
if (item->mTimeStamp == -1)
|
||
|
|
return true;
|
||
|
|
|
||
|
|
const bool isDue = item->mTimeStamp < mExpectedPresentTime;
|
||
|
|
|
||
|
|
// Ignore timestamps more than a second in the future, timestamp is us
|
||
|
|
const bool isPlausible = item->mTimeStamp < (mExpectedPresentTime + s2ns(1)/1000);
|
||
|
|
|
||
|
|
return isDue || !isPlausible;
|
||
|
|
}
|
||
|
|
|
||
|
|
bool MesonLayer::shouldPresentNow(const std::shared_ptr<VtBufferItem> item)
|
||
|
|
{
|
||
|
|
if (!item.get())
|
||
|
|
return false;
|
||
|
|
|
||
|
|
if (item->mTimeStamp == -1)
|
||
|
|
return true;
|
||
|
|
|
||
|
|
const bool isDue = item->mTimeStamp < mExpectedPresentTime;
|
||
|
|
|
||
|
|
// Ignore timestamps more than a second in the future, timestamp is us
|
||
|
|
const bool isPlausible = item->mTimeStamp < (mExpectedPresentTime + s2ns(1)/1000);
|
||
|
|
|
||
|
|
return isDue || !isPlausible;
|
||
|
|
}
|
||
|
|
|
||
|
|
void MesonLayer::dropExpiredFrame(bool drop)
|
||
|
|
{
|
||
|
|
int expiredItemCount = 0;
|
||
|
|
int dropCount = 0;
|
||
|
|
|
||
|
|
for (auto it = mQueueItems.begin(); it != mQueueItems.end(); it++) {
|
||
|
|
if ((*it)->mTimeStamp > 0 && shouldPresentNow((*it))) {
|
||
|
|
if (drop)
|
||
|
|
expiredItemCount++;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// drop expiredItemCount - 1 buffers
|
||
|
|
dropCount = expiredItemCount - 1;
|
||
|
|
while (true) {
|
||
|
|
auto bufItem = mQueueItems.front();
|
||
|
|
|
||
|
|
if (dropCount <= 0) {
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
|
||
|
|
meson_vt_release_buffer(mTunnelFd, mTunnelId, bufItem->mBufferFd, -1);
|
||
|
|
|
||
|
|
mQueueItems.pop_front();
|
||
|
|
dropCount--;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void MesonLayer::updateBuffer()
|
||
|
|
{
|
||
|
|
if (!isVtBuffer()) {
|
||
|
|
int buffer_fd = 0;
|
||
|
|
int fence_fd = 0;
|
||
|
|
int64_t present_time = 0;
|
||
|
|
|
||
|
|
while (meson_vt_acquire_buffer(mTunnelFd, mTunnelId, &buffer_fd, &fence_fd, &present_time) == 0) {
|
||
|
|
struct uvm_fd_info info = { 0 };
|
||
|
|
std::shared_ptr<VtBufferItem> item =
|
||
|
|
std::make_shared<VtBufferItem>(buffer_fd, present_time, info);
|
||
|
|
mQueueItems.push_back(item);
|
||
|
|
}
|
||
|
|
|
||
|
|
if (mQueueItems.empty())
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
dropExpiredFrame(true);
|
||
|
|
|
||
|
|
mUpdated = true;
|
||
|
|
mCurBufferItem = mQueueItems[0];
|
||
|
|
|
||
|
|
int width = mSourceCrop.right - mSourceCrop.left;
|
||
|
|
int height = mSourceCrop.bottom - mSourceCrop.top;
|
||
|
|
if (shouldPresentNow(mCurBufferItem)) {
|
||
|
|
setBufferInfo(width, height, VIDEO_ALIGN(width), DRM_FORMAT_NV21);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void MesonLayer::setDiProcessorFd(int32_t fd) {
|
||
|
|
std::lock_guard<std::mutex> lock(mMutex);
|
||
|
|
|
||
|
|
// do not dup fd
|
||
|
|
if (mDifd >= 0)
|
||
|
|
close(mDifd);
|
||
|
|
|
||
|
|
if (fd >= 0)
|
||
|
|
DISPLAY_LOGV("[%s] [%d] [%" PRIu64 "] set %d to DIFd (%d)",
|
||
|
|
__func__, mDisplayId, mId, getBufferFdLocked(), fd);
|
||
|
|
mDifd = fd;
|
||
|
|
}
|
||
|
|
|
||
|
|
int32_t MesonLayer::getBufferFdLocked(source_type_t & sourceType)
|
||
|
|
{
|
||
|
|
int curFd = -1;
|
||
|
|
int prevFd = -1;
|
||
|
|
int32_t fd = -1;
|
||
|
|
|
||
|
|
if (mFbType == DRM_FB_VIDEO_TUNNEL_SIDEBAND)
|
||
|
|
sourceType = DTV_FIX_TUNNEL;
|
||
|
|
else
|
||
|
|
sourceType = NORMAL_TYPE;
|
||
|
|
|
||
|
|
if (mDifd >= 0) {
|
||
|
|
fd = mDifd;
|
||
|
|
} else if (mFbType == DRM_FB_VIDEO_DMABUF ||
|
||
|
|
mFbType == DRM_FB_VIDEO_UVM_DMA ||
|
||
|
|
mFbType == DRM_FB_VIDEO_TUNNEL_SIDEBAND) {
|
||
|
|
if (mCurBufferItem.get())
|
||
|
|
curFd = mCurBufferItem->mBufferFd;
|
||
|
|
|
||
|
|
if (mPrevBufferItem.get())
|
||
|
|
prevFd = mPrevBufferItem->mBufferFd;
|
||
|
|
|
||
|
|
if (shouldPresentNow(mCurBufferItem)) {
|
||
|
|
fd = (mUpdated || mVtUpdate) ? curFd : prevFd;
|
||
|
|
} else {
|
||
|
|
fd = prevFd;
|
||
|
|
}
|
||
|
|
} else if (mFbType == DRM_FB_VIDEO_COMPOSE_OUTPUT) {
|
||
|
|
fd = mFd;
|
||
|
|
}
|
||
|
|
|
||
|
|
return fd;
|
||
|
|
}
|
||
|
|
|
||
|
|
int32_t MesonLayer::getBufferFdLocked()
|
||
|
|
{
|
||
|
|
source_type_t type;
|
||
|
|
return getBufferFdLocked(type);
|
||
|
|
}
|
||
|
|
|
||
|
|
int32_t MesonLayer::getBufferFd(source_type_t & sourceType)
|
||
|
|
{
|
||
|
|
std::lock_guard<std::mutex> lock(mMutex);
|
||
|
|
return getBufferFdLocked(sourceType);
|
||
|
|
}
|
||
|
|
|
||
|
|
int32_t MesonLayer::getBufferFd()
|
||
|
|
{
|
||
|
|
std::lock_guard<std::mutex> lock(mMutex);
|
||
|
|
return getBufferFdLocked();
|
||
|
|
}
|
||
|
|
|
||
|
|
int32_t MesonLayer::releaseBuffer()
|
||
|
|
{
|
||
|
|
std::lock_guard<std::mutex> lock(mMutex);
|
||
|
|
int32_t ret = 0;
|
||
|
|
|
||
|
|
if (!mCurBufferItem.get() && mPrevBufferItem.get())
|
||
|
|
mPrevBufferItem->setReleaseFence(mCurReleaseFence);
|
||
|
|
|
||
|
|
if (!mUpdated) {
|
||
|
|
DISPLAY_LOGV("[%s] [%d] [%" PRIu64 "] vt buffer not update", __func__, mDisplayId, mId);
|
||
|
|
return -EAGAIN;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!mCurBufferItem.get()) {
|
||
|
|
DISPLAY_LOGV("[%s] [%d] [%" PRIu64 "] current buffer item is nullprt !!",
|
||
|
|
__func__, mDisplayId, mId);
|
||
|
|
return -EAGAIN;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (shouldPresentNow(mCurBufferItem) == false) {
|
||
|
|
DISPLAY_LOGV("[%s] [%d] [%" PRIu64 "] current buffer not present, timestamp not meet",
|
||
|
|
__func__, mDisplayId, mId);
|
||
|
|
return -EAGAIN;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (mQueueItems.empty()) {
|
||
|
|
DISPLAY_LOGV("[%s] [%d] [%" PRIu64 "] Queued vtbuffer is empty!!",
|
||
|
|
__func__, mDisplayId, mId);
|
||
|
|
return -EAGAIN;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!mCurReleaseFence.get() && !mPrevBufferItem.get()) {
|
||
|
|
/* TODO: this first buffer not send to display, need refresh */
|
||
|
|
DISPLAY_LOGV("[%s] [%d] [%" PRIu64 "] first buffer not display", __func__, mDisplayId, mId);
|
||
|
|
return -EAGAIN;
|
||
|
|
}
|
||
|
|
|
||
|
|
// remove it from the queueItems
|
||
|
|
mQueueItems.pop_front();
|
||
|
|
mCurBufferItem->setReleaseFence(mCurReleaseFence);
|
||
|
|
mUpdated = false;
|
||
|
|
setCurReleaseFence(-1);
|
||
|
|
|
||
|
|
// First release vt buffer, save to the previous
|
||
|
|
if (!mPrevBufferItem.get()) {
|
||
|
|
mPrevBufferItem = mCurBufferItem;
|
||
|
|
mCurBufferItem.reset();
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (mPrevBufferItem.get()) {
|
||
|
|
meson_vt_release_buffer(
|
||
|
|
mTunnelFd, mTunnelId, mPrevBufferItem->mBufferFd, mPrevBufferItem->getReleaseFenceFd());
|
||
|
|
} else {
|
||
|
|
DISPLAY_LOGE("[%s] [%d] [%" PRIu64 "] previous buffer is null, it is impossible",
|
||
|
|
__func__, mDisplayId, mId);
|
||
|
|
}
|
||
|
|
|
||
|
|
mPrevBufferItem = mCurBufferItem;
|
||
|
|
mCurBufferItem.reset();
|
||
|
|
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
int32_t MesonLayer::releaseResource()
|
||
|
|
{
|
||
|
|
std::lock_guard<std::mutex> lock(mMutex);
|
||
|
|
if (mPrevBufferItem.get()) {
|
||
|
|
meson_vt_release_buffer(
|
||
|
|
mTunnelFd, mTunnelId, mPrevBufferItem->mBufferFd, mPrevBufferItem->getReleaseFenceFd());
|
||
|
|
mPrevBufferItem.reset();
|
||
|
|
}
|
||
|
|
|
||
|
|
if (mCurBufferItem.get()) {
|
||
|
|
meson_vt_release_buffer(
|
||
|
|
mTunnelFd, mTunnelId, mCurBufferItem->mBufferFd, mCurBufferItem->getReleaseFenceFd());
|
||
|
|
mQueueItems.pop_front();
|
||
|
|
mCurBufferItem.reset();
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!isVtBuffer()) {
|
||
|
|
int buffer_fd = 0;
|
||
|
|
int fence_fd = 0;
|
||
|
|
int64_t present_time = 0;
|
||
|
|
|
||
|
|
while (meson_vt_acquire_buffer(mTunnelFd, mTunnelId, &buffer_fd, &fence_fd, &present_time) == 0) {
|
||
|
|
struct uvm_fd_info info = { 0 };
|
||
|
|
std::shared_ptr<VtBufferItem> item =
|
||
|
|
std::make_shared<VtBufferItem>(buffer_fd, present_time, info);
|
||
|
|
mQueueItems.push_back(item);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// release the buffers in mQueueItems
|
||
|
|
for (auto it = mQueueItems.begin(); it != mQueueItems.end(); it++) {
|
||
|
|
meson_vt_release_buffer(
|
||
|
|
mTunnelFd, mTunnelId, (*it)->mBufferFd, (*it)->getReleaseFenceFd());
|
||
|
|
DISPLAY_LOGV("[%s] [%d] [%" PRIu64 "] release buffer queuedFrames(%d)",
|
||
|
|
__func__, mDisplayId, mId, mQueueItems.size());
|
||
|
|
}
|
||
|
|
|
||
|
|
mQueueItems.clear();
|
||
|
|
mUpdated = false;
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
int32_t MesonLayer::getAcquireFenceFd()
|
||
|
|
{
|
||
|
|
return (mAcquireFence.get() ? mAcquireFence->dup() : -1);
|
||
|
|
}
|
||
|
|
|
||
|
|
int32_t MesonLayer::setAcquireFence(int32_t fenceFd)
|
||
|
|
{
|
||
|
|
mAcquireFence.reset(new DrmFence(fenceFd));
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
void MesonLayer::setBufferInfo(int fd, int32_t acquireFence)
|
||
|
|
{
|
||
|
|
if (mFd >= 0)
|
||
|
|
close(mFd);
|
||
|
|
|
||
|
|
mFd = fd;
|
||
|
|
|
||
|
|
setAcquireFence(acquireFence);
|
||
|
|
mUpdated = true;
|
||
|
|
}
|
||
|
|
|
||
|
|
int32_t MesonLayer::getBufferInfo(
|
||
|
|
uint32_t & width, uint32_t & height, uint32_t & stride, uint32_t & format)
|
||
|
|
{
|
||
|
|
width = mBufferWidth;
|
||
|
|
height = mBufferHeight;
|
||
|
|
stride = mBufferStride;
|
||
|
|
format = mBufferFormat;
|
||
|
|
|
||
|
|
DISPLAY_LOGV("[%s] [%" PRIu64 "] width:%d height:%d stride:%d format:%d",
|
||
|
|
__func__, mId, width, height, stride, format);
|
||
|
|
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
int32_t MesonLayer::getBufferInfo(
|
||
|
|
uint32_t & width, uint32_t & height, uint32_t & stride, uint32_t & alignHeight, uint32_t & format) {
|
||
|
|
width = mBufferWidth;
|
||
|
|
height = mBufferHeight;
|
||
|
|
stride = mBufferStride;
|
||
|
|
format = mBufferFormat;
|
||
|
|
alignHeight = mBufferAlignHeight;
|
||
|
|
DISPLAY_LOGV("[%s] [%" PRIu64 "] width:%d height:%d stride:%d format:%d",
|
||
|
|
__func__, mId, width, height, stride, format);
|
||
|
|
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
void MesonLayer::setBufferInfo(
|
||
|
|
uint32_t width, uint32_t height, uint32_t stride, uint32_t format)
|
||
|
|
{
|
||
|
|
mBufferWidth = width;
|
||
|
|
mBufferHeight = height;
|
||
|
|
mBufferStride = stride;
|
||
|
|
mBufferFormat = format;
|
||
|
|
}
|
||
|
|
|
||
|
|
/* videotunnel api */
|
||
|
|
int32_t MesonLayer::onVtFrameAvailable(
|
||
|
|
std::vector<std::shared_ptr<VtBufferItem>> & items) {
|
||
|
|
mMutex.lock();
|
||
|
|
bool haveSolidBuffer = false;
|
||
|
|
|
||
|
|
/* if mNeedReleaseVtResource is true that means
|
||
|
|
* this sideband layer receive blank frame. and layer's
|
||
|
|
* type change from sideband to color.
|
||
|
|
* don't return error.
|
||
|
|
*/
|
||
|
|
if (!isVtBuffer() && !mNeedReleaseVtResource) {
|
||
|
|
DISPLAY_LOGE("[%s] [%d] [%" PRIu64 "] not videotunnel type", __func__, mDisplayId, mId);
|
||
|
|
mMutex.unlock();
|
||
|
|
return -EINVAL;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (mTunnelId < 0) {
|
||
|
|
DISPLAY_LOGE("[%s] [%d] [%" PRIu64 "] mTunnelId %d error", __func__, mDisplayId, mId, mTunnelId);
|
||
|
|
mMutex.unlock();
|
||
|
|
return -EINVAL;
|
||
|
|
}
|
||
|
|
|
||
|
|
for (auto it = items.begin(); it != items.end(); it ++) {
|
||
|
|
DISPLAY_LOGV("[%s] [%d] [%" PRIu64 "] mTunnelId %d, buffer(%s)",
|
||
|
|
__func__, mDisplayId, mId, mTunnelId, (*it)->toString().c_str());
|
||
|
|
mQueueItems.push_back(*it);
|
||
|
|
mQueuedFrames++;
|
||
|
|
if (!(*it)->mIsSolidBuffer)
|
||
|
|
attachUvmBuffer((*it)->mBufferFd);
|
||
|
|
else
|
||
|
|
haveSolidBuffer = true;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (mQueueItems.empty()) {
|
||
|
|
mMutex.unlock();
|
||
|
|
return -EAGAIN;
|
||
|
|
}
|
||
|
|
mMutex.unlock();
|
||
|
|
|
||
|
|
if (mGameMode || haveSolidBuffer)
|
||
|
|
mDisplayObserver->onFrameAvailable();
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
int32_t MesonLayer::registerConsumer() {
|
||
|
|
int32_t ret = -1;
|
||
|
|
|
||
|
|
if (mTunnelId < 0) {
|
||
|
|
DISPLAY_LOGE("[%s] [%d] [%" PRIu64 "] tunnelId is less than 0, cannot register consumer",
|
||
|
|
__func__, mDisplayId, mId);
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (mVtConsumer)
|
||
|
|
return 0;
|
||
|
|
|
||
|
|
mVtConsumer = std::make_shared<VtConsumer> (mTunnelId,
|
||
|
|
mDisplayId,
|
||
|
|
mId);
|
||
|
|
|
||
|
|
if (!mContentListener)
|
||
|
|
mContentListener = std::make_shared<VtContentChangeListener>(this);
|
||
|
|
|
||
|
|
ret = mVtConsumer->setVtContentListener(mContentListener);
|
||
|
|
if (ret < 0) {
|
||
|
|
DISPLAY_LOGE("[%s] [%d] [%" PRIu64 "] set %d content listener failed ",
|
||
|
|
__func__, mDisplayId, mId, mTunnelId);
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
ret = VtInstanceMgr::getInstance().connectInstanceLocked(mTunnelId, mVtConsumer);
|
||
|
|
if (ret >= 0)
|
||
|
|
DISPLAY_LOGD("[%s] [%d] [%" PRIu64 "] connect to instance %d seccussed",
|
||
|
|
__func__, mDisplayId, mId, mTunnelId);
|
||
|
|
else
|
||
|
|
DISPLAY_LOGE("[%s] [%d] [%" PRIu64 "] connect to instance %d failed",
|
||
|
|
__func__, mDisplayId, mId, mTunnelId);
|
||
|
|
|
||
|
|
askVtRefresh(false);
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
/* need lock VtInstanceMgr.mInstanceMutex before */
|
||
|
|
int32_t MesonLayer::unregisterConsumer() {
|
||
|
|
int32_t ret = -1;
|
||
|
|
|
||
|
|
if (mTunnelId < 0) {
|
||
|
|
DISPLAY_LOGE("[%s] [%d] [%" PRIu64 "] tunnelId is less than 0, cannot unregister consumer",
|
||
|
|
__func__, mDisplayId, mId);
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!mVtConsumer) {
|
||
|
|
DISPLAY_LOGV("[%s] [%d] [%" PRIu64 "] consumer %d not create",
|
||
|
|
__func__, mDisplayId, mId, mTunnelId);
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
memset(&mVtSourceCrop, 0, sizeof(mVtSourceCrop));
|
||
|
|
memset(&mVtDisplayFrame, 0, sizeof(mVtDisplayFrame));
|
||
|
|
|
||
|
|
ret = VtInstanceMgr::getInstance().disconnectInstanceLocked(mTunnelId, mVtConsumer);
|
||
|
|
mVtConsumer.reset();
|
||
|
|
mVtConsumer = nullptr;
|
||
|
|
|
||
|
|
mTunnelId = -1;
|
||
|
|
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
void MesonLayer::askVtRefresh(bool flag) {
|
||
|
|
VideoTunnelDev::getInstance().askRefresh(mTunnelId, flag);
|
||
|
|
}
|
||
|
|
|
||
|
|
/* layer will destroy or layer FbType changed to non-videotunnel */
|
||
|
|
int32_t MesonLayer::releaseVtResource() {
|
||
|
|
int32_t ret = 0;
|
||
|
|
|
||
|
|
VtInstanceMgr::getInstance().lockInstancesMutex();
|
||
|
|
std::lock_guard<std::mutex> lock(mMutex);
|
||
|
|
ret = releaseVtResourceLocked();
|
||
|
|
VtInstanceMgr::getInstance().unlockInstancesMutex();
|
||
|
|
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
/* need hold VtInstanceMgr::mInstanceMutex and MesonLayer::mMutex before call */
|
||
|
|
int32_t MesonLayer::releaseVtResourceLocked(bool needDisconnect) {
|
||
|
|
if (isVtBuffer() || mNeedReleaseVtResource) {
|
||
|
|
DISPLAY_LOGV("[%s] [%d] [%" PRIu64 "]", __func__, mDisplayId, mId);
|
||
|
|
if (!mVtConsumer)
|
||
|
|
return 0;
|
||
|
|
|
||
|
|
if (needDisconnect && mNeedAskRefresh ) {
|
||
|
|
askVtRefresh(true);
|
||
|
|
mNeedAskRefresh = false;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (mPrevBufferItem.get()) {
|
||
|
|
onVtFrameDisplayed(mPrevBufferItem);
|
||
|
|
mQueuedFrames--;
|
||
|
|
DISPLAY_LOGV("[%s] [%d] [%" PRIu64 "] release buffer(%s) queuedFrames(%d)",
|
||
|
|
__func__, mDisplayId, mId, mPrevBufferItem->toString().c_str(),
|
||
|
|
mQueuedFrames);
|
||
|
|
mPrevBufferItem.reset();
|
||
|
|
}
|
||
|
|
|
||
|
|
if (mCurBufferItem.get()) {
|
||
|
|
onVtFrameDisplayed(mCurBufferItem);
|
||
|
|
mQueuedFrames--;
|
||
|
|
DISPLAY_LOGV("[%s] [%d] [%" PRIu64 "] release buffer(%s) queuedFrames(%d)",
|
||
|
|
__func__, mDisplayId, mId, mCurBufferItem->toString().c_str(),
|
||
|
|
mQueuedFrames);
|
||
|
|
mQueueItems.pop_front();
|
||
|
|
mCurBufferItem.reset();
|
||
|
|
}
|
||
|
|
|
||
|
|
// release the buffers in mQueueItems
|
||
|
|
for (auto it = mQueueItems.begin(); it != mQueueItems.end(); it++) {
|
||
|
|
onVtFrameDisplayed((*it));
|
||
|
|
mQueuedFrames--;
|
||
|
|
DISPLAY_LOGV("[%s] [%d] [%" PRIu64 "] release buffer(%s) queuedFrames(%d)",
|
||
|
|
__func__, mDisplayId, mId, (*it)->toString().c_str(), mQueuedFrames);
|
||
|
|
}
|
||
|
|
|
||
|
|
mQueueItems.clear();
|
||
|
|
mVtUpdate = false;
|
||
|
|
|
||
|
|
if (mTunnelId >= 0 && needDisconnect) {
|
||
|
|
DISPLAY_LOGD("[%s] [%d] [%" PRIu64 "] Hwc2Layer release disconnect(%d) queuedFrames(%d)",
|
||
|
|
__func__, mDisplayId, mId, mTunnelId, mQueuedFrames);
|
||
|
|
unregisterConsumer();
|
||
|
|
}
|
||
|
|
|
||
|
|
mNeedReleaseVtResource = false;
|
||
|
|
}
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
int32_t MesonLayer::onVtFrameDisplayed(std::shared_ptr<VtBufferItem> & item) {
|
||
|
|
int32_t ret = -1;
|
||
|
|
if (!mVtConsumer)
|
||
|
|
return ret;
|
||
|
|
ret = mVtConsumer->onVtFrameDisplayed(item);
|
||
|
|
if (ret) {
|
||
|
|
DISPLAY_LOGV("[%s] [%d] [%" PRIu64 "] release buffer(%s) error" ,
|
||
|
|
__func__, mDisplayId, mId, item->toString().c_str());
|
||
|
|
}
|
||
|
|
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
bool MesonLayer::newGameBuffer() {
|
||
|
|
std::lock_guard<std::mutex> lock(mMutex);
|
||
|
|
bool ret = false;
|
||
|
|
if (isVtBuffer() && mGameMode) {
|
||
|
|
if (!mCurReleaseFence.get() && !mPrevBufferItem.get()) {
|
||
|
|
ret = false;
|
||
|
|
} else {
|
||
|
|
ret = (mQueueItems.size() > 0) ? true : false;
|
||
|
|
}
|
||
|
|
DISPLAY_LOGV("[%s] [%d] [%" PRIu64 "] return %d",
|
||
|
|
__func__, mDisplayId, mId, ret);
|
||
|
|
}
|
||
|
|
|
||
|
|
/* not game mode */
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
/* refresh vt layer */
|
||
|
|
void MesonLayer::vtRefresh() {
|
||
|
|
mVtRefreshed = true;
|
||
|
|
}
|
||
|
|
|
||
|
|
void MesonLayer::setVtDisplayFrame(drm_rect_t & rect) {
|
||
|
|
std::lock_guard<std::mutex> lock(mMutex);
|
||
|
|
|
||
|
|
mVtDisplayFrame.left = rect.left;
|
||
|
|
mVtDisplayFrame.top = rect.top;
|
||
|
|
mVtDisplayFrame.right = rect.right;
|
||
|
|
mVtDisplayFrame.bottom = rect.bottom;
|
||
|
|
|
||
|
|
mUpdated = true;
|
||
|
|
vtRefresh();
|
||
|
|
}
|
||
|
|
|
||
|
|
void MesonLayer::setVtSourceCrop(int32_t l, int32_t t, int32_t r, int32_t b) {
|
||
|
|
if (mVtSourceCrop.left == l && mVtSourceCrop.top == t &&
|
||
|
|
mVtSourceCrop.right == r && mVtSourceCrop.bottom == b) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
mVtSourceCrop.left = l;
|
||
|
|
mVtSourceCrop.top = t;
|
||
|
|
mVtSourceCrop.right = r;
|
||
|
|
mVtSourceCrop.bottom = b;
|
||
|
|
|
||
|
|
mUpdated = true;
|
||
|
|
vtRefresh();
|
||
|
|
}
|
||
|
|
|
||
|
|
void MesonLayer::onVtVideoGameMode(int data) {
|
||
|
|
if (data != 1 && data != 0) {
|
||
|
|
DISPLAY_LOGW("[%s] [%d] [%" PRIu64 "] get an invalid param for gameMode",
|
||
|
|
__func__, mDisplayId, mId);
|
||
|
|
} else {
|
||
|
|
mGameMode = (data == 1 ? true : false);
|
||
|
|
DISPLAY_LOGD("[%s] [%d] [%" PRIu64 "] %s video game mode",
|
||
|
|
__func__, mDisplayId, mId, mGameMode ? "enable" : "disable");
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void MesonLayer::updateVtBuffer() {
|
||
|
|
mMutex.lock();
|
||
|
|
bool haveSolidBuffer = false;
|
||
|
|
bool isVideoTypeChange = false;
|
||
|
|
int expiredItemCount = 0;
|
||
|
|
int dropCount = 0;
|
||
|
|
int64_t diffAdded = 0;
|
||
|
|
int64_t prevTimestamp = 0;
|
||
|
|
|
||
|
|
if (!isVtBuffer()) {
|
||
|
|
mMutex.unlock();
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
* getBufferFd might drop the some buffers at the head of the queue
|
||
|
|
* if there is a buffer behind them which is timely to be presented.
|
||
|
|
*/
|
||
|
|
if (mQueueItems.empty()) {
|
||
|
|
mMutex.unlock();
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (mPrevBufferItem.get())
|
||
|
|
prevTimestamp = mPrevBufferItem->mTimeStamp;
|
||
|
|
|
||
|
|
for (auto it = mQueueItems.begin(); it != mQueueItems.end(); it++) {
|
||
|
|
if ((*it)->mIsSolidBuffer)
|
||
|
|
haveSolidBuffer = true;
|
||
|
|
|
||
|
|
if ((*it)->mTimeStamp > 0 && shouldPresentNow((*it))) {
|
||
|
|
// do not drop frame in game mode
|
||
|
|
if (!mGameMode)
|
||
|
|
expiredItemCount++;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// drop expiredItemCount-1 buffers
|
||
|
|
dropCount = expiredItemCount - 1;
|
||
|
|
|
||
|
|
while (true) {
|
||
|
|
auto bufItem = mQueueItems.front();
|
||
|
|
|
||
|
|
if (haveSolidBuffer) {
|
||
|
|
if (bufItem->mIsSolidBuffer)
|
||
|
|
break;
|
||
|
|
} else if (dropCount <= 0) {
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
|
||
|
|
diffAdded = bufItem->mTimeStamp - prevTimestamp;
|
||
|
|
prevTimestamp = bufItem->mTimeStamp;
|
||
|
|
|
||
|
|
DISPLAY_LOGD("[%s] [%d] [%" PRIu64 "] vt buffer (%s) expired dropped "
|
||
|
|
"expectedPresent time(%" PRId64 ") diffAdded(%" PRId64 ") queuedFrames(%d)",
|
||
|
|
__func__, mDisplayId,mId, bufItem->toString().c_str(),
|
||
|
|
mExpectedPresentTime, diffAdded, mQueuedFrames);
|
||
|
|
collectUvmBuffer(bufItem);
|
||
|
|
onVtFrameDisplayed(bufItem);
|
||
|
|
|
||
|
|
mQueuedFrames--;
|
||
|
|
mQueueItems.pop_front();
|
||
|
|
dropCount--;
|
||
|
|
}
|
||
|
|
|
||
|
|
// update current mVtBuffer
|
||
|
|
mVtUpdate = true;
|
||
|
|
mCurBufferItem = mQueueItems[0];
|
||
|
|
|
||
|
|
if (shouldPresentNow(mCurBufferItem)) {
|
||
|
|
struct uvm_fd_info info = mCurBufferItem->mInfo;
|
||
|
|
mTunnelIdUpdate = false;
|
||
|
|
|
||
|
|
if (info.buf_width == 0 || info.buf_height == 0) {
|
||
|
|
int width = mSourceCrop.right - mSourceCrop.left;
|
||
|
|
int height = mSourceCrop.bottom - mSourceCrop.top;
|
||
|
|
setBufferInfo(width, height, VIDEO_ALIGN(width), height, info.buf_format);
|
||
|
|
setVtSourceCrop(mSourceCrop.left, mSourceCrop.top, mSourceCrop.right, mSourceCrop.bottom);
|
||
|
|
} else {
|
||
|
|
setBufferInfo(info.buf_width, info.buf_height, info.buf_stride, info.buf_height, info.buf_format);
|
||
|
|
setVtSourceCrop(info.crop_left, info.crop_top, info.crop_right, info.crop_bottom);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
diffAdded = mCurBufferItem->mTimeStamp - prevTimestamp;
|
||
|
|
DISPLAY_LOGV("[%s] [%d] [%" PRIu64 "] currentBuffer(%s) expectedPresentTime(%"
|
||
|
|
PRId64 " us) diffAdded(%" PRId64 " us) shouldPresent:%d, queueFrameSize:%zu, isVideoTypeChange:%d",
|
||
|
|
__func__, mDisplayId, mId, mCurBufferItem->toString().c_str(),mExpectedPresentTime,
|
||
|
|
diffAdded, shouldPresentNow(mCurBufferItem), mQueueItems.size(), isVideoTypeChange);
|
||
|
|
|
||
|
|
mMutex.unlock();
|
||
|
|
}
|
||
|
|
|
||
|
|
void MesonLayer::setBufferInfo(
|
||
|
|
uint32_t width, uint32_t height, uint32_t stride, uint32_t alignHeight, uint32_t format) {
|
||
|
|
mBufferWidth = width;
|
||
|
|
mBufferHeight = height;
|
||
|
|
mBufferStride = stride;
|
||
|
|
mBufferFormat = format;
|
||
|
|
mBufferAlignHeight = alignHeight;
|
||
|
|
DISPLAY_LOGD("%s[%d]: w: %d, h: %d, s: %d, f: %d", __func__, __LINE__, width, height, stride, format);
|
||
|
|
}
|
||
|
|
|
||
|
|
int32_t MesonLayer::releaseVtBuffer() {
|
||
|
|
std::lock_guard<std::mutex> lock(mMutex);
|
||
|
|
int32_t ret = 0;
|
||
|
|
if (!isVtBuffer()) {
|
||
|
|
DISPLAY_LOGD("layer:%" PRId64 " is not videotunnel layer", getUniqueId());
|
||
|
|
return -EINVAL;
|
||
|
|
}
|
||
|
|
|
||
|
|
detachUvmBuffer();
|
||
|
|
|
||
|
|
if (mVtRefreshed) {
|
||
|
|
mVtRefreshed = false;
|
||
|
|
|
||
|
|
if (!shouldPresentNow(mCurBufferItem) ||
|
||
|
|
(shouldPresentNow(mCurBufferItem) && !mVtUpdate)) {
|
||
|
|
DISPLAY_LOGV("[%s] [%" PRIu64 "] mVtRefreshed", __func__, mId);
|
||
|
|
/* set release fence */
|
||
|
|
if (mPrevBufferItem.get())
|
||
|
|
mPrevBufferItem->setReleaseFence(mCurReleaseFence);
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!mVtUpdate) {
|
||
|
|
DISPLAY_LOGV("[%s] [%d] [%" PRIu64 "] vt buffer not update", __func__, mDisplayId, mId);
|
||
|
|
return -EAGAIN;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!mCurBufferItem.get()) {
|
||
|
|
DISPLAY_LOGV("[%s] [%d] [%" PRIu64 "] current buffer item is nullprt !!",
|
||
|
|
__func__, mDisplayId, mId);
|
||
|
|
return -EAGAIN;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (shouldPresentNow(mCurBufferItem) == false) {
|
||
|
|
DISPLAY_LOGV("[%s] [%d] [%" PRIu64 "] current buffer(%s) not present, timestamp not meet",
|
||
|
|
__func__, mDisplayId, mId, mCurBufferItem->toString().c_str());
|
||
|
|
return -EAGAIN;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (mQueueItems.empty()) {
|
||
|
|
DISPLAY_LOGV("[%s] [%d] [%" PRIu64 "] Queued vtbuffer is empty!!",
|
||
|
|
__func__, mDisplayId, mId);
|
||
|
|
return -EAGAIN;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!mCurReleaseFence.get() && !mPrevBufferItem.get()) {
|
||
|
|
/* TODO: this first buffer not send to display, need refresh */
|
||
|
|
DISPLAY_LOGV("[%s] [%d] [%" PRIu64 "] first buffer not display", __func__, mDisplayId, mId);
|
||
|
|
return -EAGAIN;
|
||
|
|
}
|
||
|
|
|
||
|
|
// remove it from the queueItems
|
||
|
|
mQueueItems.pop_front();
|
||
|
|
mCurBufferItem->setReleaseFence(mCurReleaseFence);
|
||
|
|
mVtUpdate = false;
|
||
|
|
setCurReleaseFence(-1);
|
||
|
|
|
||
|
|
// First release vt buffer, save to the previous
|
||
|
|
if (!mPrevBufferItem.get()) {
|
||
|
|
mPrevBufferItem = mCurBufferItem;
|
||
|
|
mCurBufferItem.reset();
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (mPrevBufferItem.get()) {
|
||
|
|
collectUvmBuffer(mPrevBufferItem);
|
||
|
|
|
||
|
|
DISPLAY_LOGV("[%s] [%d] [%" PRIu64 "] releaseBuffer(%s), curBuffer(%s), queuedFrames(%d)",
|
||
|
|
__func__, mDisplayId, mId,mPrevBufferItem->toString().c_str(),
|
||
|
|
mCurBufferItem->toString().c_str(), mQueuedFrames);
|
||
|
|
|
||
|
|
ret = onVtFrameDisplayed(mPrevBufferItem);
|
||
|
|
} else {
|
||
|
|
DISPLAY_LOGE("[%s] [%d] [%" PRIu64 "] previous buffer is null, it is impossible",
|
||
|
|
__func__, mDisplayId, mId);
|
||
|
|
}
|
||
|
|
|
||
|
|
mQueuedFrames--;
|
||
|
|
mPrevBufferItem = mCurBufferItem;
|
||
|
|
mCurBufferItem.reset();
|
||
|
|
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
bool MesonLayer::interruptVtProcess(bool change) {
|
||
|
|
std::lock_guard<std::mutex> lock(mMutex);
|
||
|
|
if (!isVtBuffer())
|
||
|
|
return false;
|
||
|
|
|
||
|
|
if (mVideoDisplayStatus != VT_VIDEO_STATUS_SHOW) {
|
||
|
|
releaseVtResourceLocked(false);
|
||
|
|
releaseUvmResourceLock();
|
||
|
|
|
||
|
|
if (change)
|
||
|
|
mVideoDisplayStatus = VT_VIDEO_STATUS_SHOW;
|
||
|
|
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (getBufferFdLocked() < 0 && !mTunnelIdUpdate)
|
||
|
|
return true;
|
||
|
|
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
void MesonLayer::onVtVideoStatus(vt_video_status_t status) {
|
||
|
|
std::lock_guard<std::mutex> lock(mMutex);
|
||
|
|
DISPLAY_LOGD("[%s] [%d] [%" PRIu64 "] status: %s", __func__, mDisplayId, mId, vtVideoStatusToString(status));
|
||
|
|
mVideoDisplayStatus = status;
|
||
|
|
}
|
||
|
|
|
||
|
|
/* ========================== Uvm Attach =================================== */
|
||
|
|
int32_t MesonLayer::uvmDetachEnable(bool enable) {
|
||
|
|
std::lock_guard<std::mutex> lock(mMutex);
|
||
|
|
releaseUvmResourceLock();
|
||
|
|
if (mUvmDetach)
|
||
|
|
return mUvmDetach->setEnable(enable);
|
||
|
|
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
int32_t MesonLayer::attachUvmBuffer(const int bufferFd) {
|
||
|
|
if (!mUvmDetach)
|
||
|
|
mUvmDetach = std::make_shared<UvmDetach>(mId);
|
||
|
|
|
||
|
|
return mUvmDetach->attachUvmBuffer(bufferFd);
|
||
|
|
}
|
||
|
|
|
||
|
|
int32_t MesonLayer::attachUvmBuffer(const std::shared_ptr<VtBufferItem> item){
|
||
|
|
if (!item->mIsSolidBuffer)
|
||
|
|
return attachUvmBuffer(item->mBufferFd);
|
||
|
|
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
int32_t MesonLayer::detachUvmBuffer() {
|
||
|
|
if (mUvmDetach)
|
||
|
|
return mUvmDetach->detachUvmBuffer();
|
||
|
|
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
int32_t MesonLayer::collectUvmBuffer(const int fd, const int fence) {
|
||
|
|
if (mUvmDetach) {
|
||
|
|
return mUvmDetach->collectUvmBuffer(fd, fence);
|
||
|
|
} else {
|
||
|
|
if (fd >= 0) close(fd);
|
||
|
|
if (fence >= 0 ) close(fence);
|
||
|
|
}
|
||
|
|
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
int32_t MesonLayer::collectUvmBuffer(const std::shared_ptr<VtBufferItem> item) {
|
||
|
|
if (!item)
|
||
|
|
return 0;
|
||
|
|
|
||
|
|
if (!item->mIsSolidBuffer) {
|
||
|
|
int bufferFd = dup(item->mBufferFd);
|
||
|
|
int fenceFd = item->getReleaseFenceFd();
|
||
|
|
|
||
|
|
collectUvmBuffer(bufferFd, fenceFd);
|
||
|
|
}
|
||
|
|
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
int32_t MesonLayer::releaseUvmResourceLock() {
|
||
|
|
if (mPreUvmBufferFd >= 0)
|
||
|
|
close(mPreUvmBufferFd);
|
||
|
|
mPreUvmBufferFd = -1;
|
||
|
|
|
||
|
|
if (mUvmDetach)
|
||
|
|
return mUvmDetach->releaseUvmResource();
|
||
|
|
|
||
|
|
return 0;
|
||
|
|
}
|