• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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