1 /*
2 * Copyright (c) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "hgm_frame_rate_manager.h"
17
18 #include <algorithm>
19 #include "common/rs_optional_trace.h"
20 #include "common/rs_thread_handler.h"
21 #include "pipeline/rs_uni_render_judgement.h"
22 #include "hgm_config_callback_manager.h"
23 #include "hgm_core.h"
24 #include "hgm_log.h"
25 #include "parameters.h"
26 #include "rs_trace.h"
27 #include "sandbox_utils.h"
28 #include "frame_rate_report.h"
29 #include "hgm_config_callback_manager.h"
30
31 namespace OHOS {
32 namespace Rosen {
33 namespace {
34 constexpr float MARGIN = 0.00001;
35 constexpr float MIN_DRAWING_DIVISOR = 10.0f;
36 constexpr float DIVISOR_TWO = 2.0f;
37 constexpr int32_t IDLE_TIMER_EXPIRED = 200; // ms
38 constexpr int32_t IDLE_AFTER_TOUCH_UP = 3000; // ms
39 constexpr float ONE_MS_IN_NANO = 1000000.0f;
40 constexpr uint32_t UNI_RENDER_VSYNC_OFFSET = 5000000; // ns
41
42 constexpr uint32_t SCENE_BEFORE_XML = 1;
43 constexpr uint32_t SCENE_AFTER_TOUCH = 3;
44 // CAUTION: with priority
45 const std::string VOTER_NAME[] = {
46 "VOTER_THERMAL",
47 "VOTER_VIRTUALDISPLAY",
48 "VOTER_MULTI_APP",
49
50 "VOTER_XML",
51 "VOTER_LTPO",
52 "VOTER_TOUCH",
53 "VOTER_SCENE",
54 "VOTER_IDLE"
55 };
56 }
57
Init(sptr<VSyncController> rsController,sptr<VSyncController> appController,sptr<VSyncGenerator> vsyncGenerator)58 void HgmFrameRateManager::Init(sptr<VSyncController> rsController,
59 sptr<VSyncController> appController, sptr<VSyncGenerator> vsyncGenerator)
60 {
61 voters_ = std::vector<std::string>(std::begin(VOTER_NAME), std::end(VOTER_NAME));
62 auto& hgmCore = HgmCore::Instance();
63 curRefreshRateMode_ = static_cast<RefreshRateMode>(hgmCore.GetCurrentRefreshRateMode());
64
65 // hgm warning: get non active screenId in non-folding devices(from sceneboard)
66 auto screenList = hgmCore.GetScreenIds();
67 curScreenId_ = screenList.empty() ? 0 : screenList.front();
68 isLtpo_ = (GetScreenType(curScreenId_) == "LTPO");
69 std::string curScreenName = "screen" + std::to_string(curScreenId_) + "_" + (isLtpo_ ? "LTPO" : "LTPS");
70 auto configData = hgmCore.GetPolicyConfigData();
71 if (configData != nullptr) {
72 curScreenStrategyId_ = configData->screenStrategyConfigs_[curScreenName];
73 if (curScreenStrategyId_.empty()) {
74 curScreenStrategyId_ = "LTPO-DEFAULT";
75 }
76 SyncAppVote();
77 HandleIdleEvent(ADD_VOTE);
78 }
79
80 hgmCore.RegisterRefreshRateModeChangeCallback([rsController, appController](int32_t mode) {
81 if (HgmCore::Instance().IsLTPOSwitchOn()) {
82 rsController->SetPhaseOffset(0);
83 appController->SetPhaseOffset(0);
84 CreateVSyncGenerator()->SetVSyncMode(VSYNC_MODE_LTPO);
85 } else {
86 if (RSUniRenderJudgement::IsUniRender()) {
87 rsController->SetPhaseOffset(UNI_RENDER_VSYNC_OFFSET);
88 appController->SetPhaseOffset(UNI_RENDER_VSYNC_OFFSET);
89 }
90 CreateVSyncGenerator()->SetVSyncMode(VSYNC_MODE_LTPS);
91 }
92
93 HgmConfigCallbackManager::GetInstance()->SyncRefreshRateModeChangeCallback(mode);
94 });
95 controller_ = std::make_shared<HgmVSyncGeneratorController>(rsController, appController, vsyncGenerator);
96 }
97
UniProcessDataForLtpo(uint64_t timestamp,std::shared_ptr<RSRenderFrameRateLinker> rsFrameRateLinker,const FrameRateLinkerMap & appFrameRateLinkers,bool idleTimerExpired)98 void HgmFrameRateManager::UniProcessDataForLtpo(uint64_t timestamp,
99 std::shared_ptr<RSRenderFrameRateLinker> rsFrameRateLinker,
100 const FrameRateLinkerMap& appFrameRateLinkers, bool idleTimerExpired)
101 {
102 RS_TRACE_FUNC();
103 Reset();
104
105 auto& hgmCore = HgmCore::Instance();
106 FrameRateRange finalRange;
107 if (curRefreshRateMode_ == HGM_REFRESHRATE_MODE_AUTO) {
108 finalRange = rsFrameRateLinker->GetExpectedRange();
109 for (auto linker : appFrameRateLinkers) {
110 finalRange.Merge(linker.second->GetExpectedRange());
111 }
112
113 if (finalRange.IsValid()) {
114 ResetScreenTimer(curScreenId_);
115 CalcRefreshRate(curScreenId_, finalRange);
116 DeliverRefreshRateVote(0, "VOTER_LTPO", ADD_VOTE, currRefreshRate_, currRefreshRate_);
117 } else if (idleTimerExpired) {
118 // idle in ltpo
119 HandleIdleEvent(ADD_VOTE);
120 DeliverRefreshRateVote(0, "VOTER_LTPO", REMOVE_VOTE);
121 } else {
122 StartScreenTimer(curScreenId_, IDLE_TIMER_EXPIRED, nullptr, [this]() {
123 forceUpdateCallback_(true, false);
124 });
125 }
126 }
127
128 VoteRange voteResult = ProcessRefreshRateVote();
129 // max used here
130 finalRange = {voteResult.second, voteResult.second, voteResult.second};
131 CalcRefreshRate(curScreenId_, finalRange);
132
133 bool frameRateChanged = CollectFrameRateChange(finalRange, rsFrameRateLinker, appFrameRateLinkers);
134 if (hgmCore.GetLtpoEnabled() && frameRateChanged) {
135 HandleFrameRateChangeForLTPO(timestamp);
136 } else {
137 pendingRefreshRate_ = std::make_shared<uint32_t>(currRefreshRate_);
138 if (currRefreshRate_ != hgmCore.GetPendingScreenRefreshRate()) {
139 forceUpdateCallback_(false, true);
140 FrameRateReport();
141 }
142 }
143 }
144
UniProcessDataForLtps(bool idleTimerExpired)145 void HgmFrameRateManager::UniProcessDataForLtps(bool idleTimerExpired)
146 {
147 RS_TRACE_FUNC();
148 Reset();
149
150 if (idleTimerExpired) {
151 // idle in ltps
152 HandleIdleEvent(ADD_VOTE);
153 }
154
155 FrameRateRange finalRange;
156 VoteRange voteResult = ProcessRefreshRateVote();
157 auto& hgmCore = HgmCore::Instance();
158 uint32_t lastPendingRate = hgmCore.GetPendingScreenRefreshRate();
159 // max used here
160 finalRange = {voteResult.second, voteResult.second, voteResult.second};
161 CalcRefreshRate(curScreenId_, finalRange);
162 if ((currRefreshRate_ < lastPendingRate) && !isReduceAllowed_) {
163 // Can't reduce the refreshRate in ltps mode
164 RS_TRACE_NAME_FMT("Can't reduce to [%d], keep [%d] please", currRefreshRate_, lastPendingRate);
165 currRefreshRate_ = lastPendingRate;
166 }
167
168 pendingRefreshRate_ = std::make_shared<uint32_t>(currRefreshRate_);
169 if (currRefreshRate_ != hgmCore.GetPendingScreenRefreshRate()) {
170 forceUpdateCallback_(false, true);
171 FrameRateReport();
172 }
173 }
174
FrameRateReport() const175 void HgmFrameRateManager::FrameRateReport() const
176 {
177 std::unordered_map<pid_t, uint32_t> rates;
178 rates[GetRealPid()] = currRefreshRate_;
179 auto alignRate = HgmCore::Instance().GetAlignRate();
180 rates[UNI_APP_PID] = (alignRate == 0) ? currRefreshRate_ : alignRate;
181 FRAME_TRACE::FrameRateReport::GetInstance().SendFrameRates(rates);
182 }
183
CollectFrameRateChange(FrameRateRange finalRange,std::shared_ptr<RSRenderFrameRateLinker> rsFrameRateLinker,const FrameRateLinkerMap & appFrameRateLinkers)184 bool HgmFrameRateManager::CollectFrameRateChange(FrameRateRange finalRange,
185 std::shared_ptr<RSRenderFrameRateLinker> rsFrameRateLinker,
186 const FrameRateLinkerMap& appFrameRateLinkers)
187 {
188 bool frameRateChanged = false;
189 bool controllerRateChanged = false;
190 auto rsFrameRate = GetDrawingFrameRate(currRefreshRate_, finalRange);
191 controllerRate_ = rsFrameRate > 0 ? rsFrameRate : controller_->GetCurrentRate();
192 if (controllerRate_ != controller_->GetCurrentRate()) {
193 rsFrameRateLinker->SetFrameRate(controllerRate_);
194 controllerRateChanged = true;
195 frameRateChanged = true;
196 }
197
198 auto& hgmCore = HgmCore::Instance();
199 auto screenCurrentRefreshRate = hgmCore.GetScreenCurrentRefreshRate(hgmCore.GetActiveScreenId());
200 RS_TRACE_NAME_FMT("CollectFrameRateChange refreshRate: %d, rsFrameRate: %d, finalRange = (%d, %d, %d)",
201 screenCurrentRefreshRate, rsFrameRate, finalRange.min_, finalRange.max_, finalRange.preferred_);
202 RS_TRACE_INT("PreferredFrameRate", static_cast<int>(finalRange.preferred_));
203
204 for (auto linker : appFrameRateLinkers) {
205 auto appFrameRate = GetDrawingFrameRate(currRefreshRate_, linker.second->GetExpectedRange());
206 if (appFrameRate != linker.second->GetFrameRate() || controllerRateChanged) {
207 linker.second->SetFrameRate(appFrameRate);
208 appChangeData_.emplace_back(linker.second->GetId(), appFrameRate);
209 HGM_LOGD("HgmFrameRateManager: appChangeData linkerId = %{public}" PRIu64 ", %{public}d",
210 linker.second->GetId(), appFrameRate);
211 frameRateChanged = true;
212 }
213 RS_TRACE_NAME_FMT("HgmFrameRateManager::UniProcessData multiAppFrameRate: pid = %d, appFrameRate = %d, "\
214 "appRange = (%d, %d, %d)", ExtractPid(linker.first), appFrameRate, linker.second->GetExpectedRange().min_,
215 linker.second->GetExpectedRange().max_, linker.second->GetExpectedRange().preferred_);
216 }
217 return frameRateChanged;
218 }
219
HandleFrameRateChangeForLTPO(uint64_t timestamp)220 void HgmFrameRateManager::HandleFrameRateChangeForLTPO(uint64_t timestamp)
221 {
222 RSTaskMessage::RSTask task = [this]() {
223 controller_->ChangeGeneratorRate(controllerRate_, appChangeData_);
224 pendingRefreshRate_ = std::make_shared<uint32_t>(currRefreshRate_);
225 if (currRefreshRate_ != HgmCore::Instance().GetPendingScreenRefreshRate()) {
226 forceUpdateCallback_(false, true);
227 FrameRateReport();
228 }
229 };
230
231 uint64_t expectTime = timestamp + static_cast<uint64_t>(controller_->GetCurrentOffset());
232 uint64_t currTime = static_cast<uint64_t>(
233 std::chrono::duration_cast<std::chrono::nanoseconds>(
234 std::chrono::steady_clock::now().time_since_epoch()).count());
235 int64_t delayTime = std::ceil(static_cast<int64_t>(expectTime - currTime) * 1.0f / ONE_MS_IN_NANO) + 1;
236 if (delayTime <= 0) {
237 HgmTaskHandleThread::Instance().PostTask(task);
238 } else {
239 HgmTaskHandleThread::Instance().PostTask(task, delayTime);
240 }
241 }
242
CalcRefreshRate(const ScreenId id,const FrameRateRange & range)243 void HgmFrameRateManager::CalcRefreshRate(const ScreenId id, const FrameRateRange& range)
244 {
245 // Find current refreshRate by FrameRateRange. For example:
246 // 1. FrameRateRange[min, max, preferred] is [24, 48, 48], supported refreshRates
247 // of current screen are {30, 60, 90}, the result should be 30, not 60.
248 // 2. FrameRateRange[min, max, preferred] is [150, 150, 150], supported refreshRates
249 // of current screen are {30, 60, 90}, the result will be 90.
250 auto supportRefreshRateVec = HgmCore::Instance().GetScreenSupportedRefreshRates(id);
251 if (supportRefreshRateVec.empty()) {
252 return;
253 }
254 std::sort(supportRefreshRateVec.begin(), supportRefreshRateVec.end());
255 auto iter = std::lower_bound(supportRefreshRateVec.begin(), supportRefreshRateVec.end(), range.preferred_);
256 if (iter != supportRefreshRateVec.end()) {
257 currRefreshRate_ = *iter;
258 if (currRefreshRate_ > static_cast<uint32_t>(range.max_) &&
259 (iter - supportRefreshRateVec.begin()) > 0) {
260 iter--;
261 if (*iter >= static_cast<uint32_t>(range.min_) &&
262 *iter <= static_cast<uint32_t>(range.max_)) {
263 currRefreshRate_ = *iter;
264 }
265 }
266 } else {
267 currRefreshRate_ = supportRefreshRateVec.back();
268 }
269 }
270
GetDrawingFrameRate(const uint32_t refreshRate,const FrameRateRange & range)271 uint32_t HgmFrameRateManager::GetDrawingFrameRate(const uint32_t refreshRate, const FrameRateRange& range)
272 {
273 // We will find a drawing fps, which is divisible by refreshRate.
274 // If the refreshRate is 60, the options of drawing fps are 60, 30, 15, 12, etc.
275 // 1. The preferred fps is divisible by refreshRate.
276 const float currRefreshRate = static_cast<float>(refreshRate);
277 const float preferredFps = static_cast<float>(range.preferred_);
278 if (preferredFps < MARGIN || currRefreshRate < MARGIN) {
279 return 0;
280 }
281 if (std::fmodf(currRefreshRate, range.preferred_) < MARGIN) {
282 return static_cast<uint32_t>(preferredFps);
283 }
284 // 2. FrameRateRange is not dynamic, we will find the closest drawing fps to preferredFps.
285 // e.g. If the FrameRateRange of a surfaceNode is [50, 50, 50], the refreshRate is
286 // 90, the drawing fps of the surfaceNode should be 45.
287 if (!range.IsDynamic()) {
288 return static_cast<uint32_t>(currRefreshRate / std::round(refreshRate / preferredFps));
289 }
290 // 3. FrameRateRange is dynamic. We will find a divisible result in the range if possible.
291 // If several divisible options are in the range, the smoother, the better.
292 // The KPI of "smooth" is the ratio of lack.
293 // e.g. The preferred fps is 58, the refreshRate is 60. When the drawing fps is 60,
294 // we lack the least(the ratio is 2/60).
295 // The preferred fps is 34, the refreshRate is 60, the drawing fps will be 30(the ratio is 4/30).
296 int divisor = 1;
297 float drawingFps = currRefreshRate;
298 float dividedFps = currRefreshRate;
299 float currRatio = std::abs(dividedFps - preferredFps) / preferredFps;
300 float ratio = currRatio;
301 const float minDrawingFps = currRefreshRate / MIN_DRAWING_DIVISOR;
302 while (dividedFps > minDrawingFps - MARGIN) {
303 if (dividedFps < range.min_ || dividedFps <= static_cast<float>(range.preferred_) / DIVISOR_TWO) {
304 break;
305 }
306 if (dividedFps > range.max_) {
307 divisor++;
308 float preDividedFps = dividedFps;
309 dividedFps = currRefreshRate / static_cast<float>(divisor);
310 // If we cannot find a divisible result, the closer to the preferred, the better.
311 // e.g.FrameRateRange is [50, 80, 80], refreshrate is
312 // 90, the drawing frame rate is 90.
313 if (dividedFps < range.min_ && (preferredFps - dividedFps) > (preDividedFps - preferredFps)) {
314 drawingFps = preDividedFps;
315 break;
316 }
317 currRatio = std::abs(dividedFps - preferredFps) / preferredFps;
318 if (currRatio < ratio) {
319 ratio = currRatio;
320 drawingFps = dividedFps;
321 }
322 continue;
323 }
324 currRatio = std::min(std::fmodf(preferredFps, dividedFps),
325 std::fmodf(std::abs(dividedFps - preferredFps), dividedFps)) / dividedFps;
326 // When currRatio is almost zero, dividedFps is the perfect result
327 if (currRatio < MARGIN) {
328 drawingFps = dividedFps;
329 break;
330 }
331 if (currRatio < ratio) {
332 ratio = currRatio;
333 drawingFps = dividedFps;
334 }
335 divisor++;
336 dividedFps = currRefreshRate / static_cast<float>(divisor);
337 }
338 return static_cast<uint32_t>(std::round(drawingFps));
339 }
340
GetPendingRefreshRate()341 std::shared_ptr<uint32_t> HgmFrameRateManager::GetPendingRefreshRate()
342 {
343 return pendingRefreshRate_;
344 }
345
ResetPendingRefreshRate()346 void HgmFrameRateManager::ResetPendingRefreshRate()
347 {
348 pendingRefreshRate_.reset();
349 }
350
Reset()351 void HgmFrameRateManager::Reset()
352 {
353 currRefreshRate_ = 0;
354 controllerRate_ = 0;
355 pendingRefreshRate_.reset();
356 appChangeData_.clear();
357 }
358
GetExpectedFrameRate(const RSPropertyUnit unit,float velocity) const359 int32_t HgmFrameRateManager::GetExpectedFrameRate(const RSPropertyUnit unit, float velocity) const
360 {
361 switch (unit) {
362 case RSPropertyUnit::PIXEL_POSITION:
363 return GetPreferredFps("translate", PixelToMM(velocity));
364 case RSPropertyUnit::PIXEL_SIZE:
365 case RSPropertyUnit::RATIO_SCALE:
366 return GetPreferredFps("scale", PixelToMM(velocity));
367 case RSPropertyUnit::ANGLE_ROTATION:
368 return GetPreferredFps("rotation", velocity);
369 default:
370 return 0;
371 }
372 }
373
GetPreferredFps(const std::string & type,float velocity) const374 int32_t HgmFrameRateManager::GetPreferredFps(const std::string& type, float velocity) const
375 {
376 auto configData = HgmCore::Instance().GetPolicyConfigData();
377 if (!configData) {
378 return 0;
379 }
380 auto config = configData->GetRSAnimateRateConfig(curScreenStrategyId_, std::to_string(curRefreshRateMode_), type);
381 auto iter = std::find_if(config.begin(), config.end(), [&velocity](const auto& pair) {
382 return velocity >= pair.second.min && (velocity < pair.second.max || pair.second.max == -1);
383 });
384 if (iter != config.end()) {
385 RS_OPTIONAL_TRACE_NAME_FMT("GetPreferredFps: type: %s, speed: %f, rate: %d",
386 type.c_str(), velocity, iter->second.preferred_fps);
387 return iter->second.preferred_fps;
388 }
389 return 0;
390 }
391
PixelToMM(float velocity)392 float HgmFrameRateManager::PixelToMM(float velocity)
393 {
394 float velocityMM = 0.0f;
395 auto& hgmCore = HgmCore::Instance();
396 sptr<HgmScreen> hgmScreen = hgmCore.GetScreen(hgmCore.GetActiveScreenId());
397 if (hgmScreen && hgmScreen->GetPpi() > 0.f) {
398 velocityMM = velocity / hgmScreen->GetPpi() * INCH_2_MM;
399 }
400 return velocityMM;
401 }
402
GetScreenTimer(ScreenId screenId) const403 std::shared_ptr<HgmOneShotTimer> HgmFrameRateManager::GetScreenTimer(ScreenId screenId) const
404 {
405 if (auto timer = screenTimerMap_.find(screenId); timer != screenTimerMap_.end()) {
406 return timer->second;
407 }
408 return nullptr;
409 }
410
StartScreenTimer(ScreenId screenId,int32_t interval,std::function<void ()> resetCallback,std::function<void ()> expiredCallback)411 void HgmFrameRateManager::StartScreenTimer(ScreenId screenId, int32_t interval,
412 std::function<void()> resetCallback, std::function<void()> expiredCallback)
413 {
414 if (auto oldtimer = GetScreenTimer(screenId); oldtimer == nullptr) {
415 auto newTimer = std::make_shared<HgmOneShotTimer>("idle_timer" + std::to_string(screenId),
416 std::chrono::milliseconds(interval), resetCallback, expiredCallback);
417 screenTimerMap_[screenId] = newTimer;
418 newTimer->Start();
419 }
420 }
421
ResetScreenTimer(ScreenId screenId) const422 void HgmFrameRateManager::ResetScreenTimer(ScreenId screenId) const
423 {
424 if (auto timer = GetScreenTimer(screenId); timer != nullptr) {
425 timer->Reset();
426 }
427 }
428
StopScreenTimer(ScreenId screenId)429 void HgmFrameRateManager::StopScreenTimer(ScreenId screenId)
430 {
431 if (auto timer = screenTimerMap_.find(screenId); timer != screenTimerMap_.end()) {
432 screenTimerMap_.erase(timer);
433 }
434 }
435
HandleLightFactorStatus(bool isSafe)436 void HgmFrameRateManager::HandleLightFactorStatus(bool isSafe)
437 {
438 // based on the light determine whether allowed to reduce the screen refresh rate to avoid screen flicker
439 HGM_LOGI("HandleLightFactorStatus status:%{public}u", isSafe);
440 isReduceAllowed_ = isSafe;
441 }
442
HandlePackageEvent(uint32_t listSize,const std::vector<std::string> & packageList)443 void HgmFrameRateManager::HandlePackageEvent(uint32_t listSize, const std::vector<std::string>& packageList)
444 {
445 // the focus app agreed at the front of packageList
446 std::lock_guard<std::mutex> locker(pkgSceneMutex_);
447 if (listSize > 1) {
448 // hgm warning: strategy for multi app
449 DeliverRefreshRateVote(0, "VOTER_MULTI_APP", ADD_VOTE, OLED_60_HZ, OLED_60_HZ);
450 } else {
451 DeliverRefreshRateVote(0, "VOTER_MULTI_APP", REMOVE_VOTE);
452 }
453
454 std::string curPkgName = packageList.front();
455 HGM_LOGI("HandlePackageEvent curPkg:[%{public}s] pkgNum:[%{public}d]", curPkgName.c_str(), listSize);
456 if (curPkgName_ != curPkgName) {
457 curPkgName_ = curPkgName;
458 sceneStack_.clear();
459 }
460
461 SyncAppVote();
462 }
463
HandleRefreshRateEvent(pid_t pid,const EventInfo & eventInfo)464 void HgmFrameRateManager::HandleRefreshRateEvent(pid_t pid, const EventInfo& eventInfo)
465 {
466 std::string eventName = eventInfo.eventName;
467 std::lock_guard<std::mutex> lock(voteNameMutex_);
468 auto event = std::find(voters_.begin(), voters_.end(), eventName);
469 if (event == voters_.end()) {
470 HGM_LOGW("HgmFrameRateManager:unknown event, eventName is %{public}s", eventName.c_str());
471 return;
472 }
473
474 HGM_LOGI("HandleRefreshRateEvent: %{public}s(%{public}d)", eventName.c_str(), pid);
475 if (eventName == "VOTER_SCENE") {
476 HandleSceneEvent(pid, eventInfo);
477 } else if (eventName == "VOTER_VIRTUALDISPLAY") {
478 HandleVirtualDisplayEvent(pid, eventInfo);
479 } else {
480 DeliverRefreshRateVote(pid, eventName, eventInfo.eventStatus,
481 eventInfo.minRefreshRate, eventInfo.maxRefreshRate);
482 }
483 }
484
HandleTouchEvent(int32_t touchStatus)485 void HgmFrameRateManager::HandleTouchEvent(int32_t touchStatus)
486 {
487 HGM_LOGD("HandleTouchEvent status:%{public}d", touchStatus);
488 if (!isTouchEnable_) {
489 return;
490 }
491
492 if (touchStatus == TOUCH_DOWN) {
493 DeliverRefreshRateVote(0, "VOTER_TOUCH", ADD_VOTE, touchFps_, touchFps_);
494 StopScreenTimer(curScreenId_);
495 } else {
496 // idle detect used in ltps
497 StartScreenTimer(curScreenId_, IDLE_AFTER_TOUCH_UP, nullptr, [this]() {
498 forceUpdateCallback_(true, false);
499 });
500 }
501 }
502
HandleIdleEvent(bool isIdle)503 void HgmFrameRateManager::HandleIdleEvent(bool isIdle)
504 {
505 if (isIdle) {
506 HGM_LOGI("HandleIdleEvent status:%{public}u", isIdle);
507 DeliverRefreshRateVote(0, "VOTER_TOUCH", REMOVE_VOTE);
508 DeliverRefreshRateVote(0, "VOTER_IDLE", ADD_VOTE, idleFps_, idleFps_);
509 } else {
510 DeliverRefreshRateVote(0, "VOTER_IDLE", REMOVE_VOTE);
511 }
512 }
513
HandleRefreshRateMode(RefreshRateMode refreshRateMode)514 void HgmFrameRateManager::HandleRefreshRateMode(RefreshRateMode refreshRateMode)
515 {
516 HGM_LOGI("HandleRefreshRateMode curMode:%{public}d", static_cast<int>(refreshRateMode));
517 if (curRefreshRateMode_ == refreshRateMode) {
518 return;
519 }
520
521 curRefreshRateMode_ = refreshRateMode;
522 SyncAppVote();
523 HgmCore::Instance().SetLtpoConfig();
524 FrameRateReport();
525 HgmConfigCallbackManager::GetInstance()->SyncHgmConfigChangeCallback();
526 }
527
HandleScreenPowerStatus(ScreenId id,ScreenPowerStatus status)528 void HgmFrameRateManager::HandleScreenPowerStatus(ScreenId id, ScreenPowerStatus status)
529 {
530 // hgm warning: strategy for screen off
531 HGM_LOGI("HandleScreenPowerStatus curScreen:%{public}d status:%{public}d",
532 static_cast<int>(curScreenId_), static_cast<int>(status));
533 if (status != ScreenPowerStatus::POWER_STATUS_ON) {
534 return;
535 }
536 if (curScreenId_ == id) {
537 return;
538 }
539
540 auto& hgmCore = HgmCore::Instance();
541 auto screenList = hgmCore.GetScreenIds();
542 auto screenPos = find(screenList.begin(), screenList.end(), id);
543 curScreenId_ = (screenPos == screenList.end()) ? 0 : id;
544 HGM_LOGI("HandleScreenPowerStatus curScreen:%{public}d", static_cast<int>(curScreenId_));
545
546 isLtpo_ = (GetScreenType(curScreenId_) == "LTPO");
547 std::string curScreenName = "screen" + std::to_string(curScreenId_) + "_" + (isLtpo_ ? "LTPO" : "LTPS");
548
549 auto configData = hgmCore.GetPolicyConfigData();
550 if (configData != nullptr) {
551 curScreenStrategyId_ = configData->screenStrategyConfigs_[curScreenName];
552 if (curScreenStrategyId_.empty()) {
553 curScreenStrategyId_ = "LTPO-DEFAULT";
554 }
555 }
556
557 SyncAppVote();
558 hgmCore.SetLtpoConfig();
559 FrameRateReport();
560 HgmConfigCallbackManager::GetInstance()->SyncHgmConfigChangeCallback();
561
562 // hgm warning: use !isLtpo_ instead after GetDisplaySupportedModes ready
563 if (curScreenStrategyId_.find("LTPO") == std::string::npos) {
564 DeliverRefreshRateVote(0, "VOTER_LTPO", REMOVE_VOTE);
565 }
566 }
567
HandleSceneEvent(pid_t pid,EventInfo eventInfo)568 void HgmFrameRateManager::HandleSceneEvent(pid_t pid, EventInfo eventInfo)
569 {
570 std::string sceneName = eventInfo.description;
571
572 std::lock_guard<std::mutex> locker(pkgSceneMutex_);
573 std::lock_guard<std::mutex> lock(voteMutex_);
574 std::pair<std::string, pid_t> info = std::make_pair(sceneName, pid);
575 auto scenePos = find(sceneStack_.begin(), sceneStack_.end(), info);
576 if (eventInfo.eventStatus == ADD_VOTE) {
577 if (scenePos == sceneStack_.end()) {
578 sceneStack_.push_back(info);
579 MarkVoteChange();
580 }
581 } else {
582 if (scenePos != sceneStack_.end()) {
583 sceneStack_.erase(scenePos);
584 MarkVoteChange();
585 }
586 }
587 }
588
HandleVirtualDisplayEvent(pid_t pid,EventInfo eventInfo)589 void HgmFrameRateManager::HandleVirtualDisplayEvent(pid_t pid, EventInfo eventInfo)
590 {
591 std::string virtualDisplayName = eventInfo.description;
592 auto configData = HgmCore::Instance().GetPolicyConfigData();
593 if (configData == nullptr || !configData->virtualDisplaySwitch_) {
594 // disable vote from virtual display in xml
595 return;
596 }
597
598 auto virtualDisplayConfig = configData->virtualDisplayConfigs_;
599 if (virtualDisplayConfig.count(virtualDisplayName) == 0) {
600 HGM_LOGW("HandleVirtualDisplayEvent:unknow virtual display [%{public}s]", virtualDisplayName.c_str());
601 DeliverRefreshRateVote(pid, "VOTER_VIRTUALDISPLAY", eventInfo.eventStatus, OLED_60_HZ, OLED_60_HZ);
602 } else {
603 auto curStrategy = configData->strategyConfigs_[virtualDisplayConfig[virtualDisplayName]];
604 DeliverRefreshRateVote(pid, "VOTER_VIRTUALDISPLAY", ADD_VOTE, curStrategy.min, curStrategy.max);
605 }
606 }
607
SyncAppVote()608 void HgmFrameRateManager::SyncAppVote()
609 {
610 auto configData = HgmCore::Instance().GetPolicyConfigData();
611 if (configData == nullptr) {
612 return;
613 }
614 auto curScreenSetting =
615 configData->screenConfigs_[curScreenStrategyId_][std::to_string(curRefreshRateMode_)];
616 std::string curXmlStrategy;
617 if (curScreenSetting.appList.count(curPkgName_) == 0) {
618 curXmlStrategy = curScreenSetting.strategy;
619 } else {
620 curXmlStrategy = curScreenSetting.appList[curPkgName_];
621 }
622 DeliverRefreshRateVote(0, "VOTER_XML", ADD_VOTE,
623 configData->strategyConfigs_[curXmlStrategy].min, configData->strategyConfigs_[curXmlStrategy].max);
624
625 isTouchEnable_ = (configData->strategyConfigs_[curXmlStrategy].dynamicMode != 0);
626 touchFps_ = configData->strategyConfigs_[curXmlStrategy].max;
627 idleFps_ = std::max(configData->strategyConfigs_[curXmlStrategy].min, static_cast<int32_t>(OLED_60_HZ));
628 }
629
MarkVoteChange()630 void HgmFrameRateManager::MarkVoteChange()
631 {
632 isRefreshNeed_ = true;
633 if (forceUpdateCallback_ != nullptr) {
634 forceUpdateCallback_(false, true);
635 }
636 }
637
DeliverRefreshRateVote(pid_t pid,std::string eventName,bool eventStatus,uint32_t min,uint32_t max)638 void HgmFrameRateManager::DeliverRefreshRateVote(pid_t pid, std::string eventName,
639 bool eventStatus, uint32_t min, uint32_t max)
640 {
641 RS_TRACE_NAME_FMT("Deliver voter:%s(pid:%d), status:%u, value:[%d-%d]",
642 eventName.c_str(), pid, eventStatus, min, max);
643 if (min > max) {
644 HGM_LOGW("HgmFrameRateManager:invalid vote %{public}s(%{public}d):[%{public}d, %{public}d]",
645 eventName.c_str(), pid, min, max);
646 return;
647 }
648
649 std::lock_guard<std::mutex> lock(voteMutex_);
650 auto& vec = voteRecord_[eventName];
651 if ((pid == 0) && (eventStatus == REMOVE_VOTE)) {
652 if (!vec.empty()) {
653 vec.clear();
654 MarkVoteChange();
655 }
656 return;
657 }
658
659 for (auto it = vec.begin(); it != vec.end(); it++) {
660 if ((*it).first != pid) {
661 continue;
662 }
663
664 if (eventStatus == REMOVE_VOTE) {
665 it = vec.erase(it);
666 MarkVoteChange();
667 return;
668 } else {
669 if ((*it).second.first != min || (*it).second.second != max) {
670 (*it).second = std::make_pair(min, max);
671 MarkVoteChange();
672 }
673 return;
674 }
675 }
676
677 if (eventStatus == ADD_VOTE) {
678 pidRecord_.insert(pid);
679 vec.push_back(std::make_pair(pid, std::make_pair(min, max)));
680 MarkVoteChange();
681 }
682 }
683
ProcessRefreshRateVote()684 VoteRange HgmFrameRateManager::ProcessRefreshRateVote()
685 {
686 if (!isRefreshNeed_) {
687 uint32_t lastPendingRate = HgmCore::Instance().GetPendingScreenRefreshRate();
688 RS_TRACE_NAME_FMT("Process nothing, lastRate:[%d]", lastPendingRate);
689 return std::make_pair(lastPendingRate, lastPendingRate);
690 }
691 UpdateVoteRule();
692 std::lock_guard<std::mutex> voteNameLock(voteNameMutex_);
693 std::lock_guard<std::mutex> voteLock(voteMutex_);
694
695 uint32_t min = OLED_MIN_HZ;
696 uint32_t max = OLED_MAX_HZ;
697
698 for (const auto& voter : voters_) {
699 auto vec = voteRecord_[voter];
700 if (vec.empty()) {
701 continue;
702 }
703 VoteRange info = vec.back().second;
704 uint32_t minTemp = info.first;
705 uint32_t maxTemp = info.second;
706
707 RS_TRACE_NAME_FMT("Process voter:%s(pid:%d), value:[%d-%d]", voter.c_str(), vec.back().first, minTemp, maxTemp);
708 // FORMAT voter(pid):[min,max]
709 HGM_LOGI("Process: %{public}s(%{public}d):[%{public}d, %{public}d]",
710 voter.c_str(), vec.back().first, minTemp, maxTemp);
711
712 if (minTemp > min) {
713 min = minTemp;
714 if (min >= max) {
715 min = max;
716 break;
717 }
718 }
719 if (maxTemp < max) {
720 max = maxTemp;
721 if (min >= max) {
722 max = min;
723 break;
724 }
725 }
726 if (min == max) {
727 break;
728 }
729 }
730
731 isRefreshNeed_ = false;
732 HGM_LOGI("Process: Strategy:%{public}s Screen:%{public}d Mode:%{public}d -- VoteResult:{%{public}d-%{public}d}",
733 curScreenStrategyId_.c_str(), static_cast<int>(curScreenId_), curRefreshRateMode_, min, max);
734 return std::make_pair(min, max);
735 }
736
UpdateVoteRule()737 void HgmFrameRateManager::UpdateVoteRule()
738 {
739 // dynamic priority for scene
740 if (sceneStack_.empty()) {
741 // no active scene
742 DeliverRefreshRateVote(0, "VOTER_SCENE", REMOVE_VOTE);
743 return;
744 }
745 auto configData = HgmCore::Instance().GetPolicyConfigData();
746 if (configData == nullptr) {
747 return;
748 }
749 auto curScreenSceneList =
750 configData->screenConfigs_[curScreenStrategyId_][std::to_string(curRefreshRateMode_)].sceneList;
751 if (curScreenSceneList.empty()) {
752 // no scene configed in cur screen
753 return;
754 }
755
756 std::string lastScene;
757 auto scenePos = sceneStack_.rbegin();
758 for (; scenePos != sceneStack_.rend(); scenePos++) {
759 lastScene = (*scenePos).first;
760 if (curScreenSceneList.count(lastScene) != 0) {
761 break;
762 }
763 }
764 if (scenePos == sceneStack_.rend()) {
765 // no valid scene
766 DeliverRefreshRateVote(0, "VOTER_SCENE", REMOVE_VOTE);
767 return;
768 }
769 auto curSceneConfig = curScreenSceneList[lastScene];
770 uint32_t scenePriority = static_cast<uint32_t>(std::stoi(curSceneConfig.priority));
771 uint32_t min = static_cast<uint32_t>(configData->strategyConfigs_[curSceneConfig.strategy].min);
772 uint32_t max = static_cast<uint32_t>(configData->strategyConfigs_[curSceneConfig.strategy].max);
773 HGM_LOGI("UpdateVoteRule: SceneName:%{public}s", lastScene.c_str());
774 DeliverRefreshRateVote((*scenePos).second, "VOTER_SCENE", ADD_VOTE, min, max);
775
776 // restore
777 std::lock_guard<std::mutex> lock(voteNameMutex_);
778 voters_ = std::vector<std::string>(std::begin(VOTER_NAME), std::end(VOTER_NAME));
779 std::string srcScene = "VOTER_SCENE";
780 std::string dstScene = (scenePriority == SCENE_BEFORE_XML) ? "VOTER_XML" : "VOTER_TOUCH";
781
782 // priority 1: VOTER_SCENE > VOTER_XML
783 // priority 2: VOTER_SCENE > VOTER_TOUCH
784 // priority 3: VOTER_SCENE < VOTER_TOUCH
785 auto srcPos = find(voters_.begin(), voters_.end(), srcScene);
786 auto dstPos = find(voters_.begin(), voters_.end(), dstScene);
787
788 // resort
789 voters_.erase(srcPos);
790 if (scenePriority == SCENE_AFTER_TOUCH) {
791 voters_.insert(++dstPos, srcScene);
792 } else {
793 voters_.insert(dstPos, srcScene);
794 }
795 }
796
GetScreenType(ScreenId screenId)797 std::string HgmFrameRateManager::GetScreenType(ScreenId screenId)
798 {
799 // hgm warning: use GetDisplaySupportedModes instead
800 return (screenId == 0) ? "LTPO" : "LTPS";
801 }
802
CleanVote(pid_t pid)803 void HgmFrameRateManager::CleanVote(pid_t pid)
804 {
805 if (pidRecord_.count(pid) == 0) {
806 return;
807 }
808 std::lock_guard<std::mutex> lock(voteMutex_);
809 HGM_LOGW("CleanVote: i am [%{public}d], i died, clean my votes please.", pid);
810 pidRecord_.erase(pid);
811
812 for (auto& [key, value] : voteRecord_) {
813 for (auto it = value.begin(); it != value.end(); it++) {
814 if ((*it).first == pid) {
815 it = value.erase(it);
816 break;
817 }
818 }
819 }
820 }
821
822 } // namespace Rosen
823 } // namespace OHOS