• 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 "hgm_core.h"
19 #include "hgm_log.h"
20 #include "rs_trace.h"
21 
22 namespace OHOS {
23 namespace Rosen {
24 namespace {
25     constexpr float MARGIN = 0.00001;
26     constexpr int MIN_DRAWING_FPS = 10;
27 }
28 
UniProcessData(const FrameRateRangeData & data)29 void HgmFrameRateManager::UniProcessData(const FrameRateRangeData& data)
30 {
31     auto screenId = data.screenId;
32     if (screenId == INVALID_SCREEN_ID) {
33         return;
34     }
35 
36     FrameRateRange finalRange;
37     finalRange.Merge(data.rsRange);
38     for (auto appRange : data.multiAppRange) {
39         finalRange.Merge(appRange.second);
40     }
41     if (!finalRange.IsValid()) {
42         return;
43     }
44 
45     CalcRefreshRate(screenId, finalRange);
46     rsFrameRate_ = GetDrawingFrameRate(currRefreshRate_, finalRange);
47     RS_TRACE_NAME("HgmFrameRateManager:UniProcessData refreshRate:" +
48         std::to_string(static_cast<int>(currRefreshRate_)) + ", rsFrameRate:" +
49         std::to_string(static_cast<int>(rsFrameRate_)) + ", finalRange=(" +
50         std::to_string(static_cast<int>(finalRange.min_)) + ", " +
51         std::to_string(static_cast<int>(finalRange.max_)) + ", " +
52         std::to_string(static_cast<int>(finalRange.preferred_)) + ")");
53 
54     for (auto appRange : data.multiAppRange) {
55         multiAppFrameRate_[appRange.first] = GetDrawingFrameRate(currRefreshRate_, finalRange);
56         RS_TRACE_NAME("multiAppFrameRate:pid=" +
57             std::to_string(static_cast<int>(appRange.first)) + ", appRange=(" +
58             std::to_string(static_cast<int>(appRange.second.min_)) + ", " +
59             std::to_string(static_cast<int>(appRange.second.max_)) + ", " +
60             std::to_string(static_cast<int>(appRange.second.preferred_)) + "), frameRate=" +
61             std::to_string(static_cast<int>(multiAppFrameRate_[appRange.first])));
62     }
63     // [Temporary func]: Switch refresh rate immediately, func will be removed in the future.
64     ExecuteSwitchRefreshRate(screenId);
65 }
66 
CalcRefreshRate(const ScreenId id,const FrameRateRange & range)67 void HgmFrameRateManager::CalcRefreshRate(const ScreenId id, const FrameRateRange& range)
68 {
69     // Find current refreshRate by FrameRateRange. For example:
70     // 1. FrameRateRange[min, max, preferred] is [24, 48, 48], supported refreshRates
71     // of current screen are {30, 60, 90}, the result should be 30, not 60.
72     // 2. FrameRateRange[min, max, preferred] is [150, 150, 150], supported refreshRates
73     // of current screen are {30, 60, 90}, the result will be 90.
74     auto supportRefreshRateVec = HgmCore::Instance().GetScreenSupportedRefreshRates(id);
75     std::sort(supportRefreshRateVec.begin(), supportRefreshRateVec.end());
76     auto iter = std::lower_bound(supportRefreshRateVec.begin(), supportRefreshRateVec.end(), range.preferred_);
77     if (iter != supportRefreshRateVec.end()) {
78         currRefreshRate_ = *iter;
79         if (currRefreshRate_ > static_cast<uint32_t>(range.max_) &&
80             (iter - supportRefreshRateVec.begin()) > 0) {
81             iter--;
82             if (*iter >= static_cast<uint32_t>(range.min_) &&
83                 *iter <= static_cast<uint32_t>(range.max_)) {
84                 currRefreshRate_ = *iter;
85             }
86         }
87     } else {
88         currRefreshRate_ = supportRefreshRateVec.back();
89     }
90 }
91 
GetDrawingFrameRate(const uint32_t refreshRate,const FrameRateRange & range)92 uint32_t HgmFrameRateManager::GetDrawingFrameRate(const uint32_t refreshRate, const FrameRateRange& range)
93 {
94     // We will find a drawing fps, which is divisible by refreshRate.
95     // If the refreshRate is 60, the options of drawing fps are 60, 30, 15, 12, etc.
96     // 1. The preferred fps is divisible by refreshRate.
97     const float currRefreshRate = static_cast<float>(refreshRate);
98     const float preferredFps = static_cast<float>(range.preferred_);
99     if (std::fmodf(currRefreshRate, range.preferred_) < MARGIN) {
100         return static_cast<uint32_t>(preferredFps);
101     }
102 
103     // 2. FrameRateRange is not dynamic, we will find the closest drawing fps to preferredFps.
104     // e.g. If the FrameRateRange of a surfaceNode is [50, 50, 50], the refreshRate is
105     // 90, the drawing fps of the surfaceNode should be 45.
106     if (!range.IsDynamic()) {
107         return static_cast<uint32_t>(currRefreshRate / std::round(refreshRate / preferredFps));
108     }
109 
110     // 3. FrameRateRange is dynamic. We will find a divisible result in the range if possible.
111     // If several divisible options are in the range, the smoother, the better.
112     // The KPI of "smooth" is the ratio of lack.
113     // e.g. The preferred fps is 58, the refreshRate is 60. When the drawing fps is 60,
114     // we lack the least(the ratio is 2/60).
115     // The preferred fps is 34, the refreshRate is 60, the drawing fps will be 30(the ratio is 4/30).
116     int divisor = 1;
117     float drawingFps = currRefreshRate;
118     float dividedFps = currRefreshRate;
119     float currRatio = std::abs(dividedFps - preferredFps) / preferredFps;
120     float ratio = currRatio;
121     while (dividedFps > MIN_DRAWING_FPS - MARGIN) {
122         if (dividedFps < range.min_) {
123             break;
124         }
125         if (dividedFps > range.max_) {
126             divisor++;
127             float preDividedFps = dividedFps;
128             dividedFps = currRefreshRate / static_cast<float>(divisor);
129             // If we cannot find a divisible result, the closer to the preferred, the better.
130             // e.g.FrameRateRange is [50, 80, 80], refreshrate is
131             // 90, the drawing frame rate is 90.
132             if (dividedFps < range.min_ && (preferredFps - dividedFps) >
133                 (preDividedFps - preferredFps)) {
134                 drawingFps = preDividedFps;
135                 break;
136             }
137             currRatio = std::abs(dividedFps - preferredFps) / preferredFps;
138             if (currRatio < ratio) {
139                 ratio = currRatio;
140                 drawingFps = dividedFps;
141             }
142             continue;
143         }
144         float remainder = std::min(std::fmodf(preferredFps, dividedFps),
145             std::fmodf(std::abs(dividedFps - preferredFps), dividedFps));
146         currRatio = remainder / dividedFps;
147         // When currRatio is almost zero, dividedFps is the perfect result
148         if (currRatio < MARGIN) {
149             drawingFps = dividedFps;
150             break;
151         }
152 
153         if (currRatio < ratio) {
154             ratio = currRatio;
155             drawingFps = dividedFps;
156         }
157         divisor++;
158         dividedFps = currRefreshRate / static_cast<float>(divisor);
159     }
160     return static_cast<uint32_t>(drawingFps);
161 }
162 
ExecuteSwitchRefreshRate(const ScreenId id)163 void HgmFrameRateManager::ExecuteSwitchRefreshRate(const ScreenId id)
164 {
165     static bool refreshRateSwitch = system::GetBoolParameter("persist.hgm.refreshrate.enabled", false);
166     if (!refreshRateSwitch) {
167         HGM_LOGD("HgmFrameRateManager: refreshRateSwitch is off, currRefreshRate is %{public}d", currRefreshRate_);
168         return;
169     }
170     uint32_t lcdRefreshRate = HgmCore::Instance().GetScreenCurrentRefreshRate(id);
171     if (currRefreshRate_ != lcdRefreshRate) {
172         HGM_LOGD("HgmFrameRateManager: current refreshRate is %{public}d",
173             static_cast<int>(currRefreshRate_));
174         int status = HgmCore::Instance().SetScreenRefreshRate(id, 0, currRefreshRate_);
175         if (status < EXEC_SUCCESS) {
176             currRefreshRate_ = lcdRefreshRate;
177             HGM_LOGE("HgmFrameRateManager: failed to set refreshRate %{public}d, screenId %{public}d",
178                 static_cast<int>(currRefreshRate_), static_cast<int>(id));
179         }
180     }
181 }
182 
Reset()183 void HgmFrameRateManager::Reset()
184 {
185     currRefreshRate_ = -1;
186     rsFrameRate_ = -1;
187     multiAppFrameRate_.clear();
188 }
189 } // namespace Rosen
190 } // namespace OHOS