1472 lines
41 KiB
C++
1472 lines
41 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 "MesonDisplay.h"
|
|
#include "V2DComposer.h"
|
|
#include "DisplayThread.h"
|
|
#include "MultiplanesComposition.h"
|
|
#include "DispAdptLog.h"
|
|
#include "MesonEventListener.h"
|
|
#include "VtAllocSolidColorBuffer.h"
|
|
#include "VideoTunnelDev.h"
|
|
|
|
#ifdef VSC_ENABLE
|
|
#include "VscalerEvent.h"
|
|
#endif
|
|
|
|
MesonDisplay::MesonDisplay(uint32_t display)
|
|
{
|
|
mDisplayId = display;
|
|
mDisplayToMainPlane = false;
|
|
mEnablePrimaryPlane = true;
|
|
mDelayLatency = 0;
|
|
mVsyncTimestamp = 0;
|
|
mLayerSeq = 0;
|
|
mPipe = std::make_shared<MesonDisplayPipe>(display);
|
|
mProcessorsManager = std::make_shared<ProcessorsManager>(
|
|
(display == 0) ? true : false);
|
|
mPipeAdapter = std::make_shared<VideoPipeAdapter>();
|
|
}
|
|
|
|
MesonDisplay::~MesonDisplay()
|
|
{
|
|
DISPLAY_LOGD("%s[%d]", __func__, __LINE__);
|
|
if (mPipe.get())
|
|
mPipe->destroyThread();
|
|
|
|
if (mDisplayThread.get())
|
|
mDisplayThread->destroyThread();
|
|
|
|
if (mVsync.get()) {
|
|
mVsync->setEnabled(false);
|
|
mVsync->setObserver(NULL);
|
|
mVsync.reset();
|
|
}
|
|
|
|
mLayers.clear();
|
|
for (auto planeIt = mPlanes.begin(); planeIt != mPlanes.end(); ++planeIt)
|
|
(*planeIt)->setPlane(NULL, 0, BLANK_FOR_NO_CONTENT);
|
|
mPlanes.clear();
|
|
mComposers.clear();
|
|
|
|
mCompositionStrategy.reset();
|
|
mPresentCompositionStg.reset();
|
|
mProcessorsManager.reset();
|
|
|
|
mPipe.reset();
|
|
mPipeAdapter.reset();
|
|
|
|
if (mListener.get())
|
|
mListener.reset();
|
|
|
|
VtAllocSolidColorBuffer::resetInstance();
|
|
VideoTunnelDev::resetInstanceForTest();
|
|
}
|
|
|
|
int32_t MesonDisplay::initialize()
|
|
{
|
|
std::vector<std::shared_ptr<IComposer>> composers;
|
|
|
|
const char *env = getenv("DISPLAYADAPTER_ENABLE_PRIMARY_PLANE");
|
|
if (env && atoi(env) != 1)
|
|
mEnablePrimaryPlane = false;
|
|
|
|
getComposers(composers);
|
|
for (auto it = composers.begin(); it != composers.end(); it++) {
|
|
mComposers.emplace(2, std::move(*it));
|
|
}
|
|
|
|
if (mPipe.get()) {
|
|
if (mEnablePrimaryPlane)
|
|
mPipe->enablePrimaryPlane();
|
|
mPipe->getCrtc(mCrtc);
|
|
mPipe->getConnector(mConnector);
|
|
mPipe->getPlanes(mPlanes);
|
|
for (auto & plane : mPlanes) {
|
|
plane->setCrtcId(mCrtc->getId());
|
|
}
|
|
|
|
#ifdef VSC_ENABLE
|
|
if (mCrtc.get() && mConnector.get())
|
|
mCrtc->setConnectorType(mConnector->getType());
|
|
#endif
|
|
}
|
|
|
|
mListener = std::make_shared<MesonEventListener>(this, ADPT_LISTENER_DIR);
|
|
mListener->registerHandler(IN_CLOSE_WRITE | IN_CREATE | IN_DELETE);
|
|
mListener->addWatch(ADPT_VIDEO, [this](const std::string& path, int mask) {
|
|
char data[STR_LEN] = { 0 };
|
|
int state = 0;
|
|
if (mask & IN_CLOSE_WRITE) {
|
|
DispAdptReadFile(path.c_str(), data, true, STR_LEN);
|
|
if (sscanf(data, "%d", &state) == 1)
|
|
this->setVideoPlaneState(state);
|
|
}
|
|
});
|
|
|
|
mListener->addWatch(DEBUG_LOG, [this](const std::string& path, int mask) {
|
|
char data[STR_LEN] = { 0 };
|
|
if (mask & IN_CLOSE_WRITE) {
|
|
DispAdptReadFile(path.c_str(), data, true, STR_LEN);
|
|
DispAdptDebugSetting(data);
|
|
}
|
|
});
|
|
|
|
mCompositionStrategy = std::make_shared<MultiplanesComposition>();
|
|
|
|
std::shared_ptr<HwDisplayCrtcBase> crtc =
|
|
std::static_pointer_cast<HwDisplayCrtcBase>(mCrtc);
|
|
std::shared_ptr<HwcVsyncBase> mesonVsync =
|
|
std::make_shared<HwcVsyncBase>(DISPLAY_DEFAULT);
|
|
|
|
mesonVsync->setVsyncMode(VSYNC_MODE_HW, crtc);
|
|
setVsync(mesonVsync);
|
|
|
|
if (!mDisplayThread.get()) {
|
|
mDisplayThread = std::make_shared<DisplayThread>(this);
|
|
}
|
|
mesonVsync->setEnabled(true);
|
|
|
|
initLayerIdGenerator();
|
|
return 0;
|
|
}
|
|
|
|
int32_t MesonDisplay::createV2DComposer(int idx,
|
|
std::shared_ptr<IComposer> & composer) {
|
|
int ret = 0;
|
|
int fd = -1;
|
|
char path[64] = { 0 };
|
|
|
|
snprintf(path, 64, "/dev/v2d.%u", idx);
|
|
fd = open(path, O_RDWR, 0);
|
|
if (fd >= 0) {
|
|
DISPLAY_LOGD("create V2DComposer for %s succeed", path);
|
|
composer = std::make_shared<V2DComposer>(mDisplayId, fd);
|
|
} else {
|
|
DISPLAY_LOGE("create V2DComposer for %s failed: %s", path, strerror(errno));
|
|
ret = -1;
|
|
}
|
|
|
|
if (fd >= 0)
|
|
close(fd);
|
|
|
|
return ret;
|
|
}
|
|
|
|
void MesonDisplay::getComposers(std::vector<std::shared_ptr<IComposer>> & composers)
|
|
{
|
|
int idx = 0;
|
|
int ret;
|
|
|
|
std::shared_ptr<IComposer> composer;
|
|
while (true) {
|
|
char path[64];
|
|
snprintf(path, 64, "/dev/v2d.%u", idx);
|
|
if (access(path, R_OK | W_OK) == 0)
|
|
idx ++;
|
|
else
|
|
break;
|
|
}
|
|
|
|
int id = mEnablePrimaryPlane ? 0 : 1;
|
|
composers.clear();
|
|
for (auto i = id; i < idx; i++) {
|
|
ret = createV2DComposer(i, composer);
|
|
if (ret)
|
|
return;
|
|
else
|
|
composers.push_back(std::move(composer));
|
|
}
|
|
}
|
|
|
|
/*
|
|
LayerId is 16bits.
|
|
Higher 8 Bits: now is 256 layer slot, the higher 8 bits is the slot index.
|
|
Lower 8 Bits: a sequence no, used to distinguish layers have same slot index (
|
|
which may happened a layer destroyed and at the same time a new layer created.)
|
|
*/
|
|
#define MAX_MESON_LAYERS (256)
|
|
#define LAYER_SLOT_BITS (8)
|
|
|
|
void MesonDisplay::initLayerIdGenerator()
|
|
{
|
|
mLayersBitmap = std::make_shared<BitsMap>(MAX_MESON_LAYERS);
|
|
mLayerSeq = 0;
|
|
}
|
|
|
|
uint32_t MesonDisplay::createLayerId()
|
|
{
|
|
uint32_t layerId = 0;
|
|
int idx = mLayersBitmap->getZeroBit();
|
|
mLayersBitmap->setBit(idx);
|
|
|
|
mLayerSeq++;
|
|
mLayerSeq %= MAX_MESON_LAYERS;
|
|
|
|
layerId = ((idx & (MAX_MESON_LAYERS - 1)) << LAYER_SLOT_BITS) | mLayerSeq;
|
|
return layerId;
|
|
}
|
|
|
|
void MesonDisplay::destroyLayerId(uint32_t id)
|
|
{
|
|
int slotIdx = id >> LAYER_SLOT_BITS;
|
|
mLayersBitmap->clearBit(slotIdx);
|
|
}
|
|
|
|
void MesonDisplay::registerCallback(int32_t layerId, void *context, meson_callback_t *cb)
|
|
{
|
|
std::lock_guard<std::mutex> lock(mMutex);
|
|
auto layerIt = mLayers.find(layerId);
|
|
if (layerIt != mLayers.end())
|
|
layerIt->second->registerCallback(context, cb);
|
|
}
|
|
|
|
void MesonDisplay::registerPageFlipCallBack(int32_t layerId, void *context, adpt_page_flip_callback *cb)
|
|
{
|
|
std::lock_guard<std::mutex> lock(mMutex);
|
|
auto layerIt = mLayers.find(layerId);
|
|
if (layerIt != mLayers.end())
|
|
layerIt->second->registerPageFlipCallBack(context, cb);
|
|
|
|
if (mPipe.get())
|
|
mPipe->drmPageFlipInit();
|
|
}
|
|
|
|
int MesonDisplay::createLayer(int32_t &outLayer)
|
|
{
|
|
std::lock_guard<std::mutex> lock(mMutex);
|
|
std::shared_ptr<MesonLayer> layer = std::make_shared<MesonLayer>(mDisplayId);
|
|
uint32_t idx = createLayerId();
|
|
outLayer = idx;
|
|
|
|
layer->setUniqueId(outLayer);
|
|
mLayers.emplace(outLayer, layer);
|
|
|
|
return MESON_ERROR_NONE;
|
|
}
|
|
|
|
int MesonDisplay::destroyLayer(int32_t inLayer)
|
|
{
|
|
std::lock_guard<std::mutex> lock(mMutex);
|
|
auto layerit = mLayers.find(inLayer);
|
|
if (layerit == mLayers.end())
|
|
return MESON_ERROR_BAD_LAYER;
|
|
|
|
std::shared_ptr<MesonLayer> layer = layerit->second;
|
|
mLayers.erase(inLayer);
|
|
destroyLayerId(inLayer);
|
|
DISPLAY_LOGD("%s[%d]: layer: %d", __func__, __LINE__, inLayer);
|
|
|
|
if (layer.get() && !layer->isVtBuffer())
|
|
layer->releaseResource();
|
|
|
|
if (layer.get() && layer->isVtBuffer())
|
|
layer->releaseVtResource();
|
|
|
|
if (mPipe.get())
|
|
mPipe->destroyPageFlip(inLayer);
|
|
|
|
if (layer->keepFrame()) {
|
|
for (auto planeIt = mPlanes.begin(); planeIt != mPlanes.end(); ++planeIt)
|
|
(*planeIt)->setKeepFrame();
|
|
return MESON_ERROR_HAS_CHANGES;
|
|
}
|
|
|
|
return MESON_ERROR_NONE;
|
|
}
|
|
|
|
int32_t MesonDisplay::setTunnelId(int32_t layer, int32_t tunnelId)
|
|
{
|
|
std::lock_guard<std::mutex> lock(mMutex);
|
|
std::shared_ptr<VtDisplayObserver> observer = std::make_shared<VtDisplayObserver>(this);
|
|
|
|
if (tunnelId < 128 && tunnelId >= 0)
|
|
VtAllocSolidColorBuffer::getInstance().allocBuffer();
|
|
|
|
auto layerIt = mLayers.find(layer);
|
|
if (layerIt != mLayers.end())
|
|
return layerIt->second->setTunnelId(tunnelId, std::move(observer));
|
|
return -1;
|
|
}
|
|
|
|
int32_t MesonDisplay::setLayerIndex(int32_t layer, int32_t index)
|
|
{
|
|
std::lock_guard<std::mutex> lock(mMutex);
|
|
auto layerIt = mLayers.find(layer);
|
|
if (layerIt != mLayers.end()) {
|
|
if (index < MAX_LAYER_NUMBER && !(mState & (1 << index)))
|
|
layerIt->second->setVisible(false);
|
|
return layerIt->second->setIndex(index);
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
int32_t MesonDisplay::setLayerZorder(int32_t layer, int32_t zorder)
|
|
{
|
|
std::lock_guard<std::mutex> lock(mMutex);
|
|
auto layerIt = mLayers.find(layer);
|
|
if (layerIt != mLayers.end())
|
|
return layerIt->second->setZorder(zorder);
|
|
return -1;
|
|
}
|
|
|
|
int32_t MesonDisplay::setLayerSourceCrop(int32_t layerId, struct rect crop)
|
|
{
|
|
std::lock_guard<std::mutex> lock(mMutex);
|
|
drm_rect_t layer_crop;
|
|
auto layerIt = mLayers.find(layerId);
|
|
|
|
layer_crop.left = crop.x;
|
|
layer_crop.top = crop.y;
|
|
layer_crop.right = crop.x + crop.w;
|
|
layer_crop.bottom = crop.y + crop.h;
|
|
if (layerIt != mLayers.end())
|
|
return layerIt->second->setSourceCrop(layer_crop);
|
|
return -1;
|
|
}
|
|
|
|
int32_t MesonDisplay::setLayerDispFrame(int32_t layer, drm_rect_t frame)
|
|
{
|
|
std::lock_guard<std::mutex> lock(mMutex);
|
|
auto layerIt = mLayers.find(layer);
|
|
if (layerIt != mLayers.end()) {
|
|
return layerIt->second->setDisplayFrame(frame);
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
void MesonDisplay::setVsyncDelayLatency(int32_t latency)
|
|
{
|
|
#ifdef VSC_ENABLE
|
|
int delayTime = getVideoDelay(DEFAULT_FPS);
|
|
if (mDelayLatency != delayTime) {
|
|
mDelayLatency = delayTime;
|
|
uint8_t dat[3] = {0};
|
|
uint16_t time = delayTime;
|
|
VscEventType vEventType = { 0 };
|
|
VscalerEvent *vEvent = &(VscalerEvent::getInstance());
|
|
dat[1] = time & 0xff;
|
|
dat[2] = (time >> 8) & 0xff;
|
|
vEventType = vEvent->makeEventData(mDisplayId,
|
|
V4L2_CID_EXT_VSC_SUBSCRIBE_VIDEO_DELAY,
|
|
dat, 3);
|
|
vEvent->addEventToQueue(vEventType);
|
|
}
|
|
#else
|
|
mDelayLatency = latency;
|
|
#endif
|
|
}
|
|
|
|
int32_t MesonDisplay::getVsyncDelayLatency(int32_t layer)
|
|
{
|
|
return mDelayLatency;
|
|
}
|
|
|
|
void MesonDisplay::setVideoPlaneState(int state)
|
|
{
|
|
std::lock_guard<std::mutex> lock(mMutex);
|
|
std::string value = VIDEO_ENABLE;
|
|
bool visible = true;
|
|
int index = -1;
|
|
int change = mState != -1 ? mState ^ state : 0xf;
|
|
|
|
if (change != 0) {
|
|
if (state == 0) {
|
|
value = VIDEO_DISABLE;
|
|
}
|
|
|
|
if (mDisableValue != value)
|
|
DispAdptWriteFile(DISABLE_VIDEO, value.c_str());
|
|
|
|
mDisableValue = std::move(value);
|
|
|
|
for (auto it = mLayers.begin(); it != mLayers.end(); it++) {
|
|
index = it->second->getIndex();
|
|
|
|
if (index < 0 || index >= MAX_LAYER_NUMBER)
|
|
continue;
|
|
|
|
if ((change & (1U << BASE_SHIFT_LEFT(index))) == 0)
|
|
continue;
|
|
|
|
visible = false;
|
|
if (state & (1U << BASE_SHIFT_LEFT(index)))
|
|
visible = true;
|
|
it->second->setVisible(visible);
|
|
}
|
|
}
|
|
mState = state;
|
|
DISPLAY_LOGV("%s[%d]: state: 0x%x, change: 0x%x", __func__, __LINE__, state, change);
|
|
}
|
|
|
|
int32_t MesonDisplay::getUiSize(int32_t* width, int32_t* height)
|
|
{
|
|
if (width == nullptr || height == nullptr) {
|
|
DISPLAY_LOGE("Invalid pointer: width or height is null");
|
|
return -1;
|
|
}
|
|
|
|
*width = DISPLAY_WIDTH_BASE;
|
|
*height = DISPLAY_HEIGHT_BASE;
|
|
return 0;
|
|
}
|
|
|
|
int32_t MesonDisplay::setVideoDisplaytoMainplane()
|
|
{
|
|
char path_select[MESON_MAX_STR_LEN] = { 0 };
|
|
int vd1, vd2, vd3;
|
|
int ret;
|
|
|
|
if (mEnablePrimaryPlane)
|
|
return 0;
|
|
|
|
ret = DispAdptReadFile(VIDEO_PATH_SELECT, path_select, true, MESON_MAX_STR_LEN);
|
|
|
|
if (ret) {
|
|
DISPLAY_LOGE("read file(%s) fail", VIDEO_PATH_SELECT);
|
|
return ret;
|
|
}
|
|
|
|
if (sscanf(path_select, "vd1: %d vd2: %d, vd3: %d", &vd1, &vd2, &vd3) == 3) {
|
|
memset(path_select, 0, sizeof(path_select));
|
|
sprintf(path_select, "%d %d %d", vd2, vd1, vd3);
|
|
DispAdptWriteFile(VIDEO_PATH_SELECT, path_select);
|
|
DispAdptWriteFile(DISABLE_VIDEO, "0");
|
|
DispAdptWriteFile(VIDEO_TEST_PATTERN, "0 1 0xff");
|
|
DispAdptWriteFile(VIDEO_TEST_PATTERN, "0 0 0xff");
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int32_t MesonDisplay::setLayerTransform(int32_t layer, int32_t transform)
|
|
{
|
|
std::lock_guard<std::mutex> lock(mMutex);
|
|
auto layerIt = mLayers.find(layer);
|
|
if (layerIt != mLayers.end()) {
|
|
switch (transform) {
|
|
case ROTATION_90:
|
|
transform = TRANSFORM_ROT_90;
|
|
break;
|
|
case ROTATION_270:
|
|
transform = TRANSFORM_ROT_270;
|
|
break;
|
|
case ROTATION_180:
|
|
transform = TRANSFORM_ROT_180;
|
|
break;
|
|
default:
|
|
transform = TRANSFORM_NONE;
|
|
break;
|
|
}
|
|
return layerIt->second->setTransform(transform);
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
int32_t MesonDisplay::getVideoDelay(int fps)
|
|
{
|
|
int refresh = 0;
|
|
int video_delay = 0;
|
|
int vsync_time = 0;
|
|
int drm_delay = 0;
|
|
|
|
if (mPipe.get())
|
|
refresh = mPipe->getVrefresh();
|
|
|
|
vsync_time = refresh > 0 ? 1000 / refresh : 0;
|
|
drm_delay = 3 * vsync_time;
|
|
|
|
if (mPipeAdapter.get())
|
|
video_delay = mPipeAdapter->getVideoDelay(fps, refresh * 1000);
|
|
|
|
if (video_delay < 0)
|
|
video_delay = 0;
|
|
|
|
if (video_delay > std::numeric_limits<int>::max() - drm_delay)
|
|
video_delay = 0;
|
|
|
|
return video_delay + drm_delay;
|
|
}
|
|
|
|
int32_t MesonDisplay::waitVBlank()
|
|
{
|
|
if (!mCrtc.get()) {
|
|
return -EFAULT;
|
|
}
|
|
std::shared_ptr<DrmCrtc> localCrtc = mCrtc;
|
|
|
|
nsecs_t vsyncTime = 0;
|
|
int ret = localCrtc->waitVBlank(vsyncTime);
|
|
|
|
localCrtc.reset();
|
|
return ret;
|
|
}
|
|
|
|
int MesonDisplay::getLayerTotal()
|
|
{
|
|
std::lock_guard<std::mutex> lock(mMutex);
|
|
return mLayers.size();
|
|
}
|
|
|
|
int32_t MesonDisplay::setVsync(std::shared_ptr<HwcVsyncBase> vsync)
|
|
{
|
|
std::lock_guard<std::mutex> lock(mMutex);
|
|
int vsyncType = vsync->getVsyncType();
|
|
switch (vsyncType) {
|
|
case DISPLAY_DEFAULT:
|
|
if (mVsync != vsync) {
|
|
if (mVsync.get()) {
|
|
mVsync->setEnabled(false);
|
|
mVsync->setObserver(NULL);
|
|
} else {
|
|
mVsync = std::move(vsync);
|
|
mVsync->setObserver(this);
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
DISPLAY_LOGE("Get invalid vsync");
|
|
break;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void MesonDisplay::onVsync(int64_t timestamp, uint32_t vsyncPeriodNanos, int vsyncType)
|
|
{
|
|
switch (vsyncType) {
|
|
case DISPLAY_DEFAULT:
|
|
mVsyncTimestamp = timestamp;
|
|
if (mDisplayThread.get()) {
|
|
mDisplayThread->onVsync(timestamp, vsyncPeriodNanos);
|
|
} else {
|
|
DISPLAY_LOGE("MesonDisplay (%p) mDisplayThread is NULL", this);
|
|
}
|
|
break;
|
|
default:
|
|
DISPLAY_LOGE("onVsync get invalid vsync");
|
|
break;
|
|
}
|
|
}
|
|
|
|
void MesonDisplay::setLayersPresentTime()
|
|
{
|
|
std::lock_guard<std::mutex> vtLock(mMutex);
|
|
|
|
nsecs_t period = 1e9 / 60;
|
|
|
|
nsecs_t expectPresentedTime = mVsyncTimestamp + period;
|
|
|
|
for (auto it = mLayers.begin(); it != mLayers.end(); it++) {
|
|
// expectPresent time is current vsync timestamp + 1 vsyncPeriod
|
|
it->second->setPresentTime(expectPresentedTime);
|
|
}
|
|
}
|
|
|
|
int MesonDisplay::collectLayersForPresent() {
|
|
/*
|
|
* 1) add reference to Layers to keep it alive during display.
|
|
* 2) for special layer, update its composition type.
|
|
* 3) sort Layers by zorder for composition.
|
|
*/
|
|
mPresentLayers.reserve(10);
|
|
|
|
for (auto it = mLayers.begin(); it != mLayers.end(); it++) {
|
|
mPresentLayers.push_back(it->second);
|
|
mFbs.insert(make_pair(it->second->getCurZorder(), it->second));
|
|
}
|
|
return MESON_ERROR_NONE;
|
|
}
|
|
|
|
int MesonDisplay::collectPlanesForPresent() {
|
|
mPresentPlanes = mPlanes;
|
|
return MESON_ERROR_NONE;
|
|
}
|
|
|
|
int MesonDisplay::collectComposersForPresent() {
|
|
for (auto it = mComposers.begin(); it != mComposers.end(); it++) {
|
|
mPresentComposers.push_back(it->second);
|
|
}
|
|
|
|
return MESON_ERROR_NONE;
|
|
}
|
|
|
|
int MesonDisplay::collectCompositionStgForPresent() {
|
|
if (!mCompositionStrategy.get())
|
|
return MESON_ERROR_BAD_PARAMETER;
|
|
mPresentCompositionStg = mCompositionStrategy;
|
|
return MESON_ERROR_NONE;
|
|
}
|
|
|
|
int MesonDisplay::validateDisplay(uint32_t* outNumTypes,
|
|
uint32_t* outNumRequests)
|
|
{
|
|
std::lock_guard<std::mutex> lock(mMutex);
|
|
bool updateZ = true;
|
|
|
|
mPresentLayers.clear();
|
|
mPresentComposers.clear();
|
|
mPresentPlanes.clear();
|
|
mPresentCompositionStg.reset();
|
|
mFbs.clear();
|
|
|
|
int ret = collectLayersForPresent();
|
|
if (ret != MESON_ERROR_NONE) {
|
|
return ret;
|
|
}
|
|
ret = collectComposersForPresent();
|
|
if (ret != MESON_ERROR_NONE) {
|
|
return ret;
|
|
}
|
|
ret = collectPlanesForPresent();
|
|
if (ret != MESON_ERROR_NONE) {
|
|
return ret;
|
|
}
|
|
ret = collectCompositionStgForPresent();
|
|
if (ret != MESON_ERROR_NONE) {
|
|
return ret;
|
|
}
|
|
|
|
if (mFbs.size() != mLayers.size())
|
|
updateZ = false;
|
|
|
|
/*setup composition strategy.*/
|
|
std::vector<std::shared_ptr<DrmFramebufferBase>> fbs;
|
|
auto fbIt = mPresentLayers.begin();
|
|
for (; fbIt != mPresentLayers.end(); fbIt++) {
|
|
if (updateZ)
|
|
(*fbIt)->updateZorder();
|
|
fbs.push_back(std::static_pointer_cast<DrmFramebufferBase>(*fbIt));
|
|
}
|
|
|
|
std::vector<std::shared_ptr<HwDisplayPlaneBase>> planes;
|
|
auto planeIt = mPresentPlanes.begin();
|
|
for (; planeIt != mPresentPlanes.end(); planeIt++) {
|
|
if ((*planeIt)->getPrimary() || !mDisplayToMainPlane)
|
|
planes.push_back(std::static_pointer_cast<HwDisplayPlaneBase>(*planeIt));
|
|
}
|
|
|
|
std::list<DisplayPair> prevDisplayPairs;
|
|
std::list<DisplayPair> currDisplayPairs;
|
|
mPresentCompositionStg->getDisplayPair(prevDisplayPairs);
|
|
|
|
std::shared_ptr<HwDisplayCrtcBase> crtc =
|
|
std::static_pointer_cast<HwDisplayCrtcBase>(mCrtc);
|
|
mPresentCompositionStg->setup(fbs, mPresentComposers,
|
|
planes, crtc, 0, 0, { 0 });
|
|
|
|
if (mPresentCompositionStg->decideComposition() < 0)
|
|
return MESON_ERROR_NO_RESOURCES;
|
|
|
|
mPresentCompositionStg->getDisplayPair(currDisplayPairs);
|
|
if (currDisplayPairs != prevDisplayPairs) {
|
|
for (auto displayIt = currDisplayPairs.begin(); displayIt != currDisplayPairs.end(); ++displayIt) {
|
|
std::shared_ptr<MesonLayer> fb =
|
|
std::static_pointer_cast<MesonLayer>(*(displayIt->fbs.begin()));
|
|
fb->froceRefresh(true);
|
|
}
|
|
}
|
|
|
|
if (mProcessorsManager.get()) {
|
|
std::list<DisplayPair> displayPairs;
|
|
mPresentCompositionStg->getDisplayPair(displayPairs);
|
|
mProcessorsManager->setup(std::move(displayPairs), 0);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int MesonDisplay::presentDisplay(int32_t* outPresentFence)
|
|
{
|
|
int ret;
|
|
std::lock_guard<std::mutex> lock(mMutex);
|
|
bool mainThread = !hasVtBuffer();
|
|
|
|
if (mPresentCompositionStg.get() == NULL)
|
|
return MESON_ERROR_BAD_PARAMETER;
|
|
|
|
if (mProcessorsManager.get())
|
|
mProcessorsManager->runVideoProcessors(mainThread);
|
|
|
|
ret = mPresentCompositionStg->commit();
|
|
|
|
if (mProcessorsManager.get()) {
|
|
mProcessorsManager->setVideoProcessorReleaseFence(ret != 0, mainThread);
|
|
mProcessorsManager->restoretProcessorFromFreeToUnused();
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
bool MesonDisplay::handleDisplayConnection()
|
|
{
|
|
std::lock_guard<std::mutex> vtLock(mMutex);
|
|
std::shared_ptr<MesonLayer> layer;
|
|
bool ret = false;
|
|
|
|
for (auto it = mLayers.begin(); it != mLayers.end(); it++) {
|
|
layer = it->second;
|
|
if (!layer->isVtBuffer())
|
|
layer->updateBuffer();
|
|
else
|
|
layer->updateVtBuffer();
|
|
ret = true;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
void MesonDisplay::releaseLayers()
|
|
{
|
|
std::lock_guard<std::mutex> vtLock(mMutex);
|
|
int ret;
|
|
std::shared_ptr<MesonLayer> layer;
|
|
|
|
for (auto it = mLayers.begin(); it != mLayers.end(); it++) {
|
|
layer = it->second;
|
|
if (!layer->isVtBuffer()) {
|
|
ret = layer->releaseBuffer();
|
|
} else {
|
|
ret = layer->releaseVtBuffer();
|
|
}
|
|
if (ret != 0 && ret != -EAGAIN) {
|
|
DISPLAY_LOGE("%s, release layer id=%" PRIu64 " failed, ret=%d",
|
|
__func__, layer->getUniqueId(), ret);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* whether the videotunnel layer has new game buffer
|
|
*/
|
|
bool MesonDisplay::newGameBuffer() {
|
|
std::lock_guard<std::mutex> vtLock(mMutex);
|
|
for (auto it = mLayers.begin(); it != mLayers.end(); it++) {
|
|
auto layer = it->second;
|
|
if (layer && layer->newGameBuffer())
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void MesonDisplay::onFrameAvailable() {
|
|
if (mDisplayThread.get())
|
|
mDisplayThread->onFrameAvailableForGameMode();
|
|
}
|
|
|
|
bool MesonDisplay::hasVtBuffer() {
|
|
for (auto it = mLayers.begin(); it != mLayers.end(); it++) {
|
|
auto layer = it->second;
|
|
if (layer && layer->isVtBuffer())
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
#ifdef VSC_ENABLE
|
|
std::shared_ptr<MesonLayer> MesonDisplay::getLayerById(int id)
|
|
{
|
|
std::unordered_map<int, std::shared_ptr<MesonLayer>>::iterator it =
|
|
mLayers.find(id);
|
|
|
|
if (it != mLayers.end())
|
|
return it->second;
|
|
|
|
return NULL;
|
|
}
|
|
|
|
int32_t MesonDisplay::getLayerWinRegion(int32_t layerId,
|
|
struct v4l2_ext_vsc_win_region &win)
|
|
{
|
|
std::lock_guard<std::mutex> lock(mMutex);
|
|
std::shared_ptr<MesonLayer> layer = getLayerById(layerId);
|
|
if (!layer)
|
|
return MESON_ERROR_BAD_LAYER;
|
|
|
|
drm_rect_t res = layer->getSourceResolution();
|
|
drm_rect_t crop = layer->getSourceCrop();
|
|
drm_rect_t frame = layer->getDisplayFrame();
|
|
drm_rect_t punch = layer->getSourcePunch();
|
|
int rotation = 0;
|
|
|
|
switch (layer->getTransform()) {
|
|
case TRANSFORM_ROT_90:
|
|
rotation = ROTATION_90;
|
|
break;
|
|
case TRANSFORM_ROT_270:
|
|
rotation = ROTATION_270;
|
|
break;
|
|
case TRANSFORM_ROT_180:
|
|
rotation = ROTATION_180;
|
|
break;
|
|
default:
|
|
rotation = ROTATION_0;
|
|
break;
|
|
}
|
|
|
|
win.in.res.x = res.left;
|
|
win.in.res.y = res.top;
|
|
win.in.res.w = res.right - res.left;
|
|
win.in.res.h = res.bottom - res.top;
|
|
|
|
win.in.crop.x = crop.left;
|
|
win.in.crop.y = crop.top;
|
|
win.in.crop.w = crop.right - crop.left;
|
|
win.in.crop.h = crop.bottom - crop.top;
|
|
|
|
win.out.x = frame.left;
|
|
win.out.y = frame.top;
|
|
win.out.w = frame.right - frame.left;
|
|
win.out.h = frame.bottom - frame.top;
|
|
|
|
win.punch.x = punch.left;
|
|
win.punch.y = punch.top;
|
|
win.punch.w = punch.right - punch.left;
|
|
win.punch.h = punch.bottom - punch.top;
|
|
|
|
win.rotation = (enum v4l2_ext_vsc_rotation)rotation;
|
|
return 0;
|
|
}
|
|
|
|
int32_t MesonDisplay::setLayerOriginalResolution(int32_t layerId,
|
|
meson_rect_t rect, meson_rect_t win_punch)
|
|
{
|
|
std::lock_guard<std::mutex> lock(mMutex);
|
|
drm_rect_t res;
|
|
drm_rect_t punch;
|
|
std::shared_ptr<MesonLayer> layer = getLayerById(layerId);
|
|
if (!layer)
|
|
return MESON_ERROR_BAD_LAYER;
|
|
|
|
res.left = rect.left;
|
|
res.top = rect.top;
|
|
res.right = rect.right;
|
|
res.bottom = rect.bottom;
|
|
punch.left = win_punch.left;
|
|
punch.top = win_punch.top;
|
|
punch.right = win_punch.right;
|
|
punch.bottom = win_punch.bottom;
|
|
layer->setOriginalResolution(res, punch);
|
|
return 0;
|
|
}
|
|
|
|
int32_t MesonDisplay::getLayerZorder(int32_t layerId, struct v4l2_ext_vsc_zorder &z)
|
|
{
|
|
std::lock_guard<std::mutex> lock(mMutex);
|
|
std::shared_ptr<MesonLayer> layer = getLayerById(layerId);
|
|
if (!layer)
|
|
return MESON_ERROR_BAD_LAYER;
|
|
|
|
z.zorder = layer->getZorder();
|
|
z.alpha = layer->getPlaneAlpha() * 255;
|
|
return 0;
|
|
}
|
|
|
|
int32_t MesonDisplay::setLayerPlaneAlpha(int32_t layerId, float alpha)
|
|
{
|
|
std::lock_guard<std::mutex> lock(mMutex);
|
|
std::shared_ptr<MesonLayer> layer = getLayerById(layerId);
|
|
if (!layer)
|
|
return MESON_ERROR_BAD_LAYER;
|
|
|
|
return layer->setPlaneAlpha(alpha);
|
|
}
|
|
|
|
int32_t MesonDisplay::getLayerConnectInfo(int32_t layerId,
|
|
struct v4l2_ext_vsc_connect_info &info)
|
|
{
|
|
std::lock_guard<std::mutex> lock(mMutex);
|
|
std::shared_ptr<MesonLayer> layer = getLayerById(layerId);
|
|
if (!layer)
|
|
return MESON_ERROR_BAD_LAYER;
|
|
|
|
connect_info_t c_info = layer->getConnectInfo();
|
|
info.in.src = (enum v4l2_ext_vsc_input_src)c_info.src;
|
|
info.in.index = c_info.index;
|
|
info.in.attr = c_info.attr;
|
|
info.out = (enum v4l2_ext_vsc_dest)c_info.out;
|
|
return 0;
|
|
}
|
|
|
|
int32_t MesonDisplay::setLayerConnectInfo(int32_t layerId, int32_t src,
|
|
int32_t index, int32_t attr, int32_t out)
|
|
{
|
|
std::lock_guard<std::mutex> lock(mMutex);
|
|
connect_info_t c_info = {
|
|
.src = src,
|
|
.index = index,
|
|
.attr = attr,
|
|
.out = out,
|
|
};
|
|
std::shared_ptr<MesonLayer> layer = getLayerById(layerId);
|
|
if (!layer)
|
|
return MESON_ERROR_BAD_LAYER;
|
|
layer->setConnectInfo(c_info);
|
|
return 0;
|
|
}
|
|
|
|
int32_t MesonDisplay::getLayerWinProp(int32_t layerId,
|
|
struct v4l2_ext_vsc_win_prop &prop)
|
|
{
|
|
std::lock_guard<std::mutex> lock(mMutex);
|
|
std::shared_ptr<MesonLayer> layer = getLayerById(layerId);
|
|
if (!layer)
|
|
return MESON_ERROR_BAD_LAYER;
|
|
|
|
win_prop_t wprop = layer->getWinProp();
|
|
prop.win_mode = (enum v4l2_ext_vsc_win_mode)wprop.win_mode;
|
|
prop.mirror_mode = (enum v4l2_ext_vsc_mirror_mode)wprop.mirror_mode;
|
|
prop.mem_type = (enum v4l2_ext_vsc_memory_type)wprop.mem_type;
|
|
return 0;
|
|
}
|
|
|
|
int32_t MesonDisplay::setLayerWinProp(int32_t layerId, int32_t winmode,
|
|
int32_t mirrormode, int32_t memtype)
|
|
{
|
|
std::lock_guard<std::mutex> lock(mMutex);
|
|
std::shared_ptr<MesonLayer> layer = getLayerById(layerId);
|
|
if (!layer)
|
|
return MESON_ERROR_BAD_LAYER;
|
|
|
|
win_prop_t prop = {
|
|
.win_mode = winmode,
|
|
.mirror_mode = mirrormode,
|
|
.mem_type = memtype,
|
|
};
|
|
layer->setWinProp(prop);
|
|
return 0;
|
|
}
|
|
|
|
int32_t MesonDisplay::setAspectratio(int32_t layerId,
|
|
struct v4l2_ext_vsc_aspectratio_policy policy)
|
|
{
|
|
std::lock_guard<std::mutex> lock(mMutex);
|
|
std::shared_ptr<MesonLayer> layer = getLayerById(layerId);
|
|
if (!layer)
|
|
return MESON_ERROR_BAD_LAYER;
|
|
|
|
int wss_afd = 0;
|
|
struct v4l2_ext_video_rect source_rect = { 0 };
|
|
struct v4l2_ext_video_rect input_rect = { 0 };
|
|
struct v4l2_ext_video_rect output_rect = { 0 };
|
|
int w, h;
|
|
int id = layer->getTunnelId();
|
|
int ret = -1;
|
|
|
|
if (id != MESON_USE_TVIN_TUNNEL && id != MESON_USE_TVIN_EXT_TUNNEL)
|
|
wss_afd = 1;
|
|
|
|
drm_rect_t res = layer->getSourceResolution();
|
|
source_rect.x = res.left;
|
|
source_rect.y = res.top;
|
|
source_rect.w = res.right - res.left;
|
|
source_rect.h = res.bottom - res.top;
|
|
|
|
if (mPipe.get()) {
|
|
mPipe->getSize(w, h);
|
|
ret = mPipe->getAspectratio((void *)&source_rect, wss_afd,
|
|
w, h,
|
|
(void *)&policy,
|
|
(void *)&input_rect,
|
|
(void *)&output_rect);
|
|
if (!ret) {
|
|
drm_rect_t rect = {
|
|
.left = input_rect.x,
|
|
.top = input_rect.y,
|
|
.right = input_rect.x + input_rect.w,
|
|
.bottom = input_rect.y + input_rect.h,
|
|
};
|
|
|
|
drm_rect_t frame = {
|
|
.left = output_rect.x,
|
|
.top = output_rect.y,
|
|
.right = output_rect.x + output_rect.w,
|
|
.bottom = output_rect.y + output_rect.h,
|
|
};
|
|
layer->setSourceCrop(rect);
|
|
layer->setDisplayFrame(frame);
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int32_t MesonDisplay::setLayerOrbitWindow(int32_t layerId,
|
|
struct v4l2_ext_vsc_orbit_window &info)
|
|
{
|
|
std::lock_guard<std::mutex> lock(mMutex);
|
|
std::shared_ptr<MesonLayer> layer = getLayerById(layerId);
|
|
if (!layer)
|
|
return MESON_ERROR_BAD_LAYER;
|
|
|
|
int w = 0;
|
|
int h = 0;
|
|
drm_rect_t osd_input = {
|
|
.left = info.osd_input.x,
|
|
.top = info.osd_input.y,
|
|
.right = info.osd_input.w + info.osd_input.x,
|
|
.bottom = info.osd_input.h + info.osd_input.y
|
|
};
|
|
drm_rect_t video_input = {
|
|
.left = info.video_input.x,
|
|
.top = info.video_input.y,
|
|
.right = info.video_input.w + info.video_input.x,
|
|
.bottom = info.video_input.h + info.video_input.y
|
|
};
|
|
drm_rect_t osd_output = {
|
|
.left = info.osd_output.x,
|
|
.top = info.osd_output.y,
|
|
.right = info.osd_output.w + info.osd_output.x,
|
|
.bottom = info.osd_output.h + info.osd_output.y
|
|
};
|
|
drm_rect_t video_output = {
|
|
.left = info.video_output.x,
|
|
.top = info.video_output.y,
|
|
.right = info.video_output.w + info.video_output.x,
|
|
.bottom = info.video_output.h + info.video_output.y
|
|
};
|
|
|
|
if (mPipe.get())
|
|
mPipe->getSize(w, h);
|
|
|
|
return layer->setOrbitWindow(osd_input,
|
|
video_input,
|
|
osd_output,
|
|
video_output,
|
|
w, h);
|
|
}
|
|
|
|
int32_t MesonDisplay::setLayerOrbitMove(int32_t layerId,
|
|
struct v4l2_ext_vsc_orbit_move &info)
|
|
{
|
|
std::lock_guard<std::mutex> lock(mMutex);
|
|
std::shared_ptr<MesonLayer> layer = getLayerById(layerId);
|
|
if (!layer)
|
|
return MESON_ERROR_BAD_LAYER;
|
|
|
|
int w = 0;
|
|
int h = 0;
|
|
drm_rect_t osd_input = {
|
|
.left = info.osd_input.x,
|
|
.top = info.osd_input.y,
|
|
.right = info.osd_input.w + info.osd_input.x,
|
|
.bottom = info.osd_input.h + info.osd_input.y
|
|
};
|
|
drm_rect_t video_input = {
|
|
.left = info.video_input.x,
|
|
.top = info.video_input.y,
|
|
.right = info.video_input.w + info.video_input.x,
|
|
.bottom = info.video_input.h + info.video_input.y
|
|
};
|
|
drm_rect_t osd_output = {
|
|
.left = info.osd_output.x,
|
|
.top = info.osd_output.y,
|
|
.right = info.osd_output.w + info.osd_output.x,
|
|
.bottom = info.osd_output.h + info.osd_output.y
|
|
};
|
|
drm_rect_t video_output = {
|
|
.left = info.video_output.x,
|
|
.top = info.video_output.y,
|
|
.right = info.video_output.w + info.video_output.x,
|
|
.bottom = info.video_output.h + info.video_output.y
|
|
};
|
|
|
|
if (mPipe.get())
|
|
mPipe->getSize(w, h);
|
|
|
|
return layer->setOrbitMove(osd_input,
|
|
video_input,
|
|
osd_output,
|
|
video_output,
|
|
w, h);
|
|
}
|
|
|
|
int32_t MesonDisplay::getHDR()
|
|
{
|
|
std::lock_guard<std::mutex> lock(mMutex);
|
|
if (mConnector.get())
|
|
return mConnector->getHDR();
|
|
return -1;
|
|
}
|
|
|
|
int32_t MesonDisplay::setHDR(int value)
|
|
{
|
|
std::lock_guard<std::mutex> lock(mMutex);
|
|
if (mConnector.get())
|
|
return mConnector->setHDR(value);
|
|
return -1;
|
|
}
|
|
|
|
int32_t MesonDisplay::getBgColor(int *value)
|
|
{
|
|
std::lock_guard<std::mutex> lock(mMutex);
|
|
if (mCrtc.get())
|
|
*value = mCrtc->getBgColor();
|
|
return 0;
|
|
}
|
|
|
|
int32_t MesonDisplay::setBgColor(int value)
|
|
{
|
|
std::lock_guard<std::mutex> lock(mMutex);
|
|
if (mCrtc.get())
|
|
return mCrtc->setBgColor(value);
|
|
return -1;
|
|
}
|
|
|
|
int32_t MesonDisplay::getLayerFreeze(int32_t layerId, int *freeze)
|
|
{
|
|
std::lock_guard<std::mutex> lock(mMutex);
|
|
std::shared_ptr<MesonLayer> layer = getLayerById(layerId);
|
|
if (!layer)
|
|
return MESON_ERROR_BAD_LAYER;
|
|
|
|
*freeze = layer->getFreeze();
|
|
return 0;
|
|
}
|
|
|
|
int32_t MesonDisplay::setLayerFreeze(int32_t layerId, int freeze)
|
|
{
|
|
std::lock_guard<std::mutex> lock(mMutex);
|
|
std::shared_ptr<MesonLayer> layer = getLayerById(layerId);
|
|
if (!layer)
|
|
return MESON_ERROR_BAD_LAYER;
|
|
|
|
layer->setFreeze(freeze);
|
|
return 0;
|
|
}
|
|
|
|
int32_t MesonDisplay::getLayerFreezeFrameBuffer(int32_t layerId, int *freeze)
|
|
{
|
|
std::lock_guard<std::mutex> lock(mMutex);
|
|
std::shared_ptr<MesonLayer> layer = getLayerById(layerId);
|
|
if (!layer)
|
|
return MESON_ERROR_BAD_LAYER;
|
|
|
|
*freeze = layer->getFreezeBuffer();
|
|
return 0;
|
|
}
|
|
|
|
int32_t MesonDisplay::setLayerFreezeFrameBuffer(int32_t layerId, int freeze)
|
|
{
|
|
std::lock_guard<std::mutex> lock(mMutex);
|
|
std::shared_ptr<MesonLayer> layer = getLayerById(layerId);
|
|
if (!layer)
|
|
return MESON_ERROR_BAD_LAYER;
|
|
|
|
layer->setFreezeBuffer(freeze);
|
|
return 0;
|
|
}
|
|
|
|
/* hdmitx function begin */
|
|
int32_t MesonDisplay::getHdmitxConnection(int &state)
|
|
{
|
|
std::lock_guard<std::mutex> lock(mMutex);
|
|
state = 0;
|
|
if (mConnector.get())
|
|
return mConnector->getHdmitxConnection(state);
|
|
return -1;
|
|
}
|
|
|
|
int32_t MesonDisplay::getHdmitxHdrType(int &value)
|
|
{
|
|
std::lock_guard<std::mutex> lock(mMutex);
|
|
if (mConnector.get())
|
|
value = mConnector->getHDR();
|
|
return 0;
|
|
}
|
|
|
|
int32_t MesonDisplay::getHdmitxHdcpVersion(int &value)
|
|
{
|
|
std::lock_guard<std::mutex> lock(mMutex);
|
|
if (mConnector.get())
|
|
return mConnector->getHdmitxHdcpVersion(value);
|
|
return 0;
|
|
}
|
|
|
|
int32_t MesonDisplay::getHdmitxHdrPolicy(int &value)
|
|
{
|
|
std::lock_guard<std::mutex> lock(mMutex);
|
|
if (mCrtc.get())
|
|
return mCrtc->getHdmitxHdrPolicy(value);
|
|
return -1;
|
|
}
|
|
|
|
int32_t MesonDisplay::setHdmitxHdrPolicy(int value)
|
|
{
|
|
std::lock_guard<std::mutex> lock(mMutex);
|
|
if (mCrtc.get())
|
|
return mCrtc->setHdmitxHdrPolicy((ENUM_MESON_HDR_POLICY)value);
|
|
return 0;
|
|
}
|
|
|
|
int32_t MesonDisplay::setHdmitxAvMute(enum v4l2_ext_hdmitx_avmute value)
|
|
{
|
|
std::lock_guard<std::mutex> lock(mMutex);
|
|
if (mCrtc.get())
|
|
return mCrtc->setHdmitxAvMute(value);
|
|
return 0;
|
|
}
|
|
|
|
int32_t MesonDisplay::setHdmitxHdcpAuth(enum v4l2_ext_hdmitx_hdcp_auth value)
|
|
{
|
|
std::lock_guard<std::mutex> lock(mMutex);
|
|
if (mCrtc.get())
|
|
return mCrtc->setHdmitxHdcpAuth(value);
|
|
return 0;
|
|
}
|
|
|
|
int32_t MesonDisplay::getHdmitxHdcpStatus(enum v4l2_ext_hdmitx_hdcp_status &value)
|
|
{
|
|
std::lock_guard<std::mutex> lock(mMutex);
|
|
if (mConnector.get())
|
|
value = (v4l2_ext_hdmitx_hdcp_status)mConnector->getHdmitxHdcpStatus();
|
|
return 0;
|
|
}
|
|
|
|
int32_t MesonDisplay::getHdmiTiming(struct v4l2_ext_hdmitx_timing_info &info)
|
|
{
|
|
std::lock_guard<std::mutex> lock(mMutex);
|
|
int ret = -1;
|
|
if (mCrtc.get()) {
|
|
DisplayMode mode = { 0 };
|
|
ret = mCrtc->getHdmiTxMode(mode);
|
|
if (!ret) {
|
|
info.width = mode.w;
|
|
info.height = mode.h;
|
|
info.framerate = mode.vrefresh;
|
|
info.scan_type = !mode.interlace;
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int32_t MesonDisplay::setHdmiTiming(struct v4l2_ext_hdmitx_timing_info &info)
|
|
{
|
|
std::lock_guard<std::mutex> lock(mMutex);
|
|
if (mCrtc.get()) {
|
|
DisplayMode mode = { 0 };
|
|
|
|
mode.w = info.width;
|
|
mode.h = info.height;
|
|
mode.vrefresh = info.framerate;
|
|
mode.interlace = !info.scan_type;
|
|
DISPLAY_LOGV("setHdmiTxMode: w: %d, h: %d, f: %d, t: %d\n",
|
|
info.width, info.height, info.framerate, info.scan_type);
|
|
return mCrtc->setHdmiTxMode(mode);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int32_t MesonDisplay::getHdmitxColor(struct v4l2_ext_hdmitx_color_attr &attr)
|
|
{
|
|
std::lock_guard<std::mutex> lock(mMutex);
|
|
int ret = -1;
|
|
if (mConnector.get()) {
|
|
ENUM_MESON_COLOR_SPACE space;
|
|
int depth;
|
|
ret = mConnector->getHdmitxColor(space, depth);
|
|
if (!ret) {
|
|
attr.pixel_encoding = (enum v4l2_ext_hdmitx_avi_csc)space;
|
|
if (depth == 8) {
|
|
attr.color_depth = V4L2_EXT_HDMITX_COLOR_DEPTH_8BIT;
|
|
} else if (depth == 10) {
|
|
attr.color_depth = V4L2_EXT_HDMITX_COLOR_DEPTH_10BIT;
|
|
} else if (depth == 12) {
|
|
attr.color_depth = V4L2_EXT_HDMITX_COLOR_DEPTH_12BIT;
|
|
} else if (depth == 16) {
|
|
attr.color_depth = V4L2_EXT_HDMITX_COLOR_DEPTH_16BIT;
|
|
} else {
|
|
attr.color_depth = V4L2_EXT_HDMITX_COLOR_DEPTH_RESERVED;
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int32_t MesonDisplay::setHdmitxColor(struct v4l2_ext_hdmitx_color_attr attr)
|
|
{
|
|
std::lock_guard<std::mutex> lock(mMutex);
|
|
if (mConnector.get()) {
|
|
int depth = 0;
|
|
ENUM_MESON_COLOR_SPACE space;
|
|
switch (attr.color_depth) {
|
|
case V4L2_EXT_HDMITX_COLOR_DEPTH_8BIT:
|
|
depth = 8;
|
|
break;
|
|
case V4L2_EXT_HDMITX_COLOR_DEPTH_10BIT:
|
|
depth = 10;
|
|
break;
|
|
case V4L2_EXT_HDMITX_COLOR_DEPTH_12BIT:
|
|
depth = 12;
|
|
break;
|
|
case V4L2_EXT_HDMITX_COLOR_DEPTH_16BIT:
|
|
depth = 16;
|
|
break;
|
|
default:
|
|
depth = 0;
|
|
break;
|
|
}
|
|
space = (ENUM_MESON_COLOR_SPACE)attr.pixel_encoding;
|
|
return mConnector->setHdmitxColor(space, depth);
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
int32_t MesonDisplay::getHdmitxRawEdid(char **dat, int &len)
|
|
{
|
|
std::lock_guard<std::mutex> lock(mMutex);
|
|
int ret = -1;
|
|
if (!dat)
|
|
return -1;
|
|
|
|
if (mConnector.get())
|
|
ret = mConnector->getHdmitxRawEdid(dat, len);
|
|
|
|
return ret;
|
|
}
|
|
/* hdmitx function end */
|
|
|
|
void MesonDisplay::createGpscPlane(int fd)
|
|
{
|
|
std::lock_guard<std::mutex> lock(mMutex);
|
|
if (fd < 0)
|
|
return;
|
|
mGpscPlane = std::make_shared<GpscPlane>(fd);
|
|
|
|
if (mCompositionStrategy.get()) {
|
|
std::shared_ptr<MultiplanesComposition> strategy =
|
|
std::static_pointer_cast<MultiplanesComposition>(mCompositionStrategy);
|
|
strategy->setGpscPlane(mGpscPlane);
|
|
}
|
|
}
|
|
|
|
void MesonDisplay::setGpscConnectId(int id)
|
|
{
|
|
std::lock_guard<std::mutex> lock(mMutex);
|
|
if (mGpscPlane.get())
|
|
mGpscPlane->setConnectTunnel(id);
|
|
}
|
|
|
|
void MesonDisplay::clearPlane()
|
|
{
|
|
std::lock_guard<std::mutex> lock(mMutex);
|
|
for (auto planeIt = mPlanes.begin(); planeIt != mPlanes.end(); ++planeIt)
|
|
(*planeIt)->setPlane(NULL, 0, BLANK_FOR_NO_CONTENT);
|
|
|
|
if (mProcessorsManager)
|
|
mProcessorsManager->tearDownAllProcessors();
|
|
}
|
|
|
|
int MesonDisplay::setDrmLeaseFd(int fd)
|
|
{
|
|
std::lock_guard<std::mutex> lock(mMutex);
|
|
if (mConnector.get())
|
|
mConnector->setDrmLeaseFd(fd);
|
|
|
|
if (mCrtc.get())
|
|
mCrtc->setDrmLeaseFd(fd);
|
|
return 0;
|
|
}
|
|
|
|
int MesonDisplay::setOrbitPolicy(int32_t layerId,
|
|
struct v4l2_ext_vsc_orbit_policy policy)
|
|
{
|
|
int ret = -1;
|
|
struct v4l2_ext_vsc_orbit_position position = { 0 };
|
|
|
|
{
|
|
std::lock_guard<std::mutex> lock(mMutex);
|
|
std::shared_ptr<MesonLayer> layer = getLayerById(layerId);
|
|
if (!layer)
|
|
return MESON_ERROR_BAD_LAYER;
|
|
|
|
struct v4l2_ext_video_rect source_rect = { 0 };
|
|
struct v4l2_ext_video_rect input_rect = { 0 };
|
|
struct v4l2_ext_video_rect output_rect = { 0 };
|
|
|
|
layer->setOrbitPolicy(policy);
|
|
|
|
drm_rect_t res = layer->getSourceResolution();
|
|
source_rect.x = res.left;
|
|
source_rect.y = res.top;
|
|
source_rect.w = res.right - res.left;
|
|
source_rect.h = res.bottom - res.top;
|
|
|
|
drm_rect_t crop = layer->getSourceCrop();
|
|
input_rect.x = crop.left;
|
|
input_rect.y = crop.top;
|
|
input_rect.w = crop.right - crop.left;
|
|
input_rect.h = crop.bottom - crop.top;
|
|
|
|
drm_rect_t frame = layer->getDisplayFrame();
|
|
output_rect.x = frame.left;
|
|
output_rect.y = frame.top;
|
|
output_rect.w = frame.right - frame.left;
|
|
output_rect.h = frame.bottom - frame.top;
|
|
|
|
if (mPipe.get())
|
|
ret = mPipe->getOrbitPosition((void *)&source_rect,
|
|
(void *)&input_rect,
|
|
(void *)&output_rect,
|
|
(void *)&policy,
|
|
(void *)&position);
|
|
}
|
|
|
|
if (!ret) {
|
|
ret = setLayerOrbitWindow(layerId, position.orbit_window);
|
|
ret |= setLayerOrbitMove(layerId, position.orbit_move);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int MesonDisplay::getOrbitPolicy(int32_t layerId,
|
|
struct v4l2_ext_vsc_orbit_policy *policy)
|
|
{
|
|
std::lock_guard<std::mutex> lock(mMutex);
|
|
std::shared_ptr<MesonLayer> layer = getLayerById(layerId);
|
|
if (!layer)
|
|
return MESON_ERROR_BAD_LAYER;
|
|
|
|
*policy = layer->getOrbitPolicy();
|
|
return 0;
|
|
}
|
|
|
|
int MesonDisplay::setSeamlessInfo(int32_t layerId,
|
|
struct v4l2_ext_vsc_seamless_info info)
|
|
{
|
|
std::lock_guard<std::mutex> lock(mMutex);
|
|
std::shared_ptr<MesonLayer> layer = getLayerById(layerId);
|
|
if (!layer)
|
|
return MESON_ERROR_BAD_LAYER;
|
|
|
|
layer->setSeamlessInfo(info);
|
|
return 0;
|
|
}
|
|
|
|
int MesonDisplay::getSeamlessInfo(int32_t layerId,
|
|
struct v4l2_ext_vsc_seamless_info *info)
|
|
{
|
|
std::lock_guard<std::mutex> lock(mMutex);
|
|
std::shared_ptr<MesonLayer> layer = getLayerById(layerId);
|
|
if (!layer)
|
|
return MESON_ERROR_BAD_LAYER;
|
|
|
|
*info = layer->getSeamlessInfo();
|
|
return 0;
|
|
}
|
|
#endif
|