/* * 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 "DisplayThread.h" #include "DispAdptLog.h" DisplayThread::DisplayThread(MesonDisplay *display) { int32_t ret; mDisplay = display; mExit = false; needRefresh = false; snprintf(mName, 64, "DisplayThread-%d", mDisplay->getDisplayId()); ret = pthread_create(&mThread, NULL, DisplayThreadMain, (void *)this); if (ret) { DISPLAY_LOGE("%s %s, failed to create VideoTunnel CmdThread: %s", mName, __func__, strerror(ret)); } } DisplayThread::~DisplayThread() { mExit = true; pthread_join(mThread, NULL); } void DisplayThread::onVsync(int64_t timestamp, uint32_t vsyncPeriodNanos) { std::unique_lock stateLock(mMutex); needRefresh = true; stateLock.unlock(); mCondition.notify_all(); } void DisplayThread::onFrameAvailableForGameMode() { std::unique_lock stateLock(mMutex); needRefresh = true; stateLock.unlock(); mCondition.notify_all(); } void* DisplayThread::DisplayThreadMain(void *data) { DisplayThread* pThis = (DisplayThread*)data; prctl(PR_SET_NAME, "displayThread"); // set videotunnel thread to SCHED_FIFO to minimize jitter struct sched_param param = {0}; param.sched_priority = sched_get_priority_max(SCHED_FIFO); if (sched_setscheduler(0, SCHED_FIFO, ¶m) != 0) { DISPLAY_LOGE("%s %s, Couldn't set SCHED_FIFO for videotunnelthread", pThis->mName, __func__); } while (true) { if (pThis->mExit) { DISPLAY_LOGD("%s %s, VtDisplayThread exit video tunnel loop", pThis->mName, __func__); pthread_exit(0); return NULL; } pThis->handleDisplay(); } } void DisplayThread::handleDisplay() { int32_t outPresentFence = -1; long long time; std::unique_lock stateLock(mMutex); while (!needRefresh) { mCondition.wait(stateLock); } needRefresh = false; stateLock.unlock(); // run display do { mDisplay->setLayersPresentTime(); if (mDisplay->handleDisplayConnection()) { time = DispAdptGetCurrentTime(); mDisplay->validateDisplay(NULL, NULL); mDisplay->presentDisplay(&outPresentFence); mDisplay->setVsyncDelayLatency(DispAdptGetCurrentTime() - time); if (outPresentFence >= 0) close(outPresentFence); } mDisplay->releaseLayers(); } while (mDisplay->newGameBuffer()); }