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_core.h"
17
18 #include <string>
19 #include <unistd.h>
20
21 #include "hgm_log.h"
22
23 namespace OHOS::Rosen {
Instance()24 HgmCore& HgmCore::Instance()
25 {
26 static HgmCore instance;
27 if (instance.IsInit()) {
28 return instance;
29 }
30
31 if (instance.Init() == false) {
32 HGM_LOGI("HgmCore initialization failed");
33 }
34
35 return instance;
36 }
37
HgmCore()38 HgmCore::HgmCore()
39 {
40 HGM_LOGI("Construction of Hgmcore");
41 }
42
~HgmCore()43 HgmCore::~HgmCore()
44 {
45 std::lock_guard<std::mutex> lock(listMutex_);
46 HGM_LOGI("Destruction of HgmCore");
47 auto screen = screenList_.begin();
48 while (screen != screenList_.end()) {
49 screenList_.erase(screen++);
50 }
51 auto screenIdIter = screenIds_.begin();
52 while (screenIdIter != screenIds_.end()) {
53 screenIds_.erase(screenIdIter++);
54 }
55 }
56
Init()57 bool HgmCore::Init()
58 {
59 if (isInit_) {
60 return true;
61 }
62
63 if (!isEnabled_) {
64 HGM_LOGE("HgmCore Hgm is desactivated");
65 return false;
66 }
67
68 if (InitXmlConfig() != EXEC_SUCCESS) {
69 HGM_LOGE("HgmCore falied to parse");
70 return false;
71 }
72 hgmFrameRateTool_ = HgmFrameRateTool::GetInstance();
73
74 isInit_ = true;
75 HGM_LOGI("HgmCore initialization success!!!");
76 return isInit_;
77 }
78
InitXmlConfig()79 int32_t HgmCore::InitXmlConfig()
80 {
81 // parse xml configuration to hgm
82 HGM_LOGD("HgmCore is parsing xml configuration");
83 if (!mParser_) {
84 mParser_ = std::make_unique<XMLParser>();
85 }
86 if (mParser_->LoadConfiguration() != EXEC_SUCCESS) {
87 HGM_LOGE("HgmCore failed to load xml configuration file");
88 return XML_FILE_LOAD_FAIL;
89 }
90 if (mParser_->Parse()) {
91 HGM_LOGE("HgmCore failed to parse xml configuration");
92 return XML_GET_ROOT_FAIL;
93 }
94 if (!mParsedConfigData_) {
95 mParsedConfigData_ = mParser_->GetParsedData();
96 }
97 return EXEC_SUCCESS;
98 }
99
SetCustomRateMode(RefreshRateMode mode)100 int32_t HgmCore::SetCustomRateMode(RefreshRateMode mode)
101 {
102 customFrameRateMode_ = mode;
103 return EXEC_SUCCESS;
104 }
105
SetModeBySettingConfig()106 int32_t HgmCore::SetModeBySettingConfig()
107 {
108 if (!mParsedConfigData_) {
109 HGM_LOGW("HgmCore no parsed xml configuration found, failed to apply refreshrate mode");
110 return HGM_ERROR;
111 }
112
113 std::string settingTag = std::to_string(customFrameRateMode_);
114 auto mapIter = mParsedConfigData_->customerSettingConfig_.find(settingTag);
115 if (mapIter == mParsedConfigData_->customerSettingConfig_.end()) {
116 HGM_LOGW("HgmCore failed to find strategy for customer setting : %{public}d", customFrameRateMode_);
117 return HGM_ERROR;
118 }
119
120 std::string strat = mParsedConfigData_->customerSettingConfig_[settingTag];
121 auto strategy = mParsedConfigData_->detailedStrategies_.find(strat);
122 if (strategy == mParsedConfigData_->detailedStrategies_.end()) {
123 HGM_LOGW("HgmCore failed to find strategy detail for strat : %{public}s", strat.c_str());
124 return HGM_ERROR;
125 }
126 int32_t rateToSwitch = std::stoi(mParsedConfigData_->detailedStrategies_[strat].max);
127 int32_t rateFloor = std::stoi(mParsedConfigData_->detailedStrategies_[strat].min);
128
129 HGM_LOGW("HgmCore switching to rate: %{public}d via refreshrate mode, range min: %{public}d, max: %{public}d",
130 rateToSwitch, rateFloor, rateToSwitch);
131 if (rateToSwitch <= 0 || rateFloor <= 0) {
132 HGM_LOGW("HgmCore get an illegal rate via parsed config data : %{public}d", rateToSwitch);
133 return HGM_ERROR;
134 }
135
136 rateToSwitch = RequestBundlePermission(rateToSwitch);
137 for (auto &screen : screenList_) {
138 int32_t setRange = screen->SetRefreshRateRange(
139 static_cast<uint32_t>(rateFloor), static_cast<uint32_t>(rateToSwitch));
140 int32_t setThisScreen = SetScreenRefreshRate(screen->GetId(), 0, rateToSwitch);
141 if (setThisScreen != EXEC_SUCCESS || setRange != EXEC_SUCCESS) {
142 HGM_LOGW("HgmCore failed to apply refreshrate mode to screen : " PUBU64 "", screen->GetId());
143 return HGM_ERROR;
144 }
145 }
146
147 return EXEC_SUCCESS;
148 }
149
RequestBundlePermission(int32_t rate)150 int32_t HgmCore::RequestBundlePermission(int32_t rate)
151 {
152 if (rate <= OLED_60_HZ) {
153 return rate;
154 }
155
156 // black_list conatrol at 90hz, return 60 if in the list
157 if (customFrameRateMode_ == HGM_REFRESHRATE_MODE_MEDIUM) {
158 auto bundle = mParsedConfigData_->bundle_black_list_.find(currentBundleName_);
159 if (bundle != mParsedConfigData_->bundle_black_list_.end()) {
160 return OLED_60_HZ;
161 }
162 return rate;
163 }
164
165 // white_list control at 120hz, return 60 if not in the list
166 if (customFrameRateMode_ == HGM_REFRESHRATE_MODE_HIGH) {
167 auto bundle = mParsedConfigData_->bundle_white_list_.find(currentBundleName_);
168 if (bundle == mParsedConfigData_->bundle_white_list_.end()) {
169 return OLED_60_HZ;
170 }
171 return rate;
172 }
173
174 return rate;
175 }
176
SetScreenRefreshRate(ScreenId id,int32_t sceneId,int32_t rate)177 int32_t HgmCore::SetScreenRefreshRate(ScreenId id, int32_t sceneId, int32_t rate)
178 {
179 // set the screen to the desired refreshrate
180 HGM_LOGD("HgmCore setting screen " PUBU64 " to the rate of %{public}d", id, rate);
181 auto screen = GetScreen(id);
182 if (!screen) {
183 HGM_LOGW("HgmCore failed to get screen of : " PUBU64 "", id);
184 return HGM_ERROR;
185 }
186
187 if (rate <= 0) {
188 HGM_LOGW("HgmCore refuse an illegal framerate: %{public}d", rate);
189 return HGM_ERROR;
190 }
191
192 int32_t modeToSwitch = screen->SetActiveRefreshRate(sceneId, static_cast<uint32_t>(rate));
193 if (modeToSwitch < 0) {
194 return modeToSwitch;
195 }
196
197 std::lock_guard<std::mutex> lock(modeListMutex_);
198
199 // the rate is accepted and passed to a list, will be applied by hardwarethread before sending the composition
200 HGM_LOGI("HgmCore the rate of %{public}d is accepted, the target mode is %{public}d", rate, modeToSwitch);
201 if (modeListToApply_ == nullptr) {
202 HGM_LOGD("HgmCore modeListToApply_ is invalid, buiding a new mode list");
203 modeListToApply_ = std::make_unique<std::unordered_map<ScreenId, int32_t>>();
204 }
205 auto modeList = modeListToApply_.get();
206 (*modeList)[id] = modeToSwitch;
207 return modeToSwitch;
208 }
209
SetRateAndResolution(ScreenId id,int32_t sceneId,int32_t rate,int32_t width,int32_t height)210 int32_t HgmCore::SetRateAndResolution(ScreenId id, int32_t sceneId, int32_t rate, int32_t width, int32_t height)
211 {
212 // reserved
213 return HGM_ERROR;
214 }
215
SetRefreshRateMode(RefreshRateMode refreshRateMode)216 int32_t HgmCore::SetRefreshRateMode(RefreshRateMode refreshRateMode)
217 {
218 HGM_LOGD("HgmCore set refreshrate mode to : %{public}d", refreshRateMode);
219 // change refreshrate mode by setting application
220 if (SetCustomRateMode(refreshRateMode) != EXEC_SUCCESS) {
221 return HGM_ERROR;
222 }
223
224 // apply the refreshrate mode to the screen
225 if (SetModeBySettingConfig() != EXEC_SUCCESS) {
226 return HGM_ERROR;
227 }
228
229 return EXEC_SUCCESS;
230 }
231
SetDefaultRefreshRateMode()232 int32_t HgmCore::SetDefaultRefreshRateMode()
233 {
234 if (!mParsedConfigData_) {
235 HGM_LOGW("HgmCore no parsed xml configuration found, failed to apply refreshrate mode");
236 return HGM_ERROR;
237 }
238 int32_t mode = std::stoi(mParsedConfigData_->defaultRefreshRateMode_);
239 HGM_LOGD("HgmCore set default refreshrate mode to : %{public}d", mode);
240
241 if (mode == 0) {
242 return EXEC_SUCCESS;
243 }
244
245 return SetRefreshRateMode(static_cast<RefreshRateMode>(mode));
246 }
247
AddScreen(ScreenId id,int32_t defaultMode)248 int32_t HgmCore::AddScreen(ScreenId id, int32_t defaultMode)
249 {
250 // add a physical screen to hgm during hotplug event
251 HGM_LOGI("HgmCore adding screen : " PUBI64 "", id);
252 bool removeId = false;
253 for (auto screen : screenIds_) {
254 if (screen == id) {
255 removeId = true;
256 break;
257 }
258 }
259 if (removeId) {
260 if (RemoveScreen(id) != EXEC_SUCCESS) {
261 HGM_LOGW("HgmCore failed to remove the existing screen, not adding : " PUBI64 "", id);
262 return HGM_BASE_REMOVE_FAILED;
263 }
264 }
265
266 sptr<HgmScreen> newScreen = new HgmScreen(id, defaultMode);
267
268 std::lock_guard<std::mutex> lock(listMutex_);
269 screenList_.push_back(newScreen);
270 screenIds_.push_back(id);
271
272 int32_t screenNum = GetScreenListSize();
273 HGM_LOGI("HgmCore num of screen is %{public}d", screenNum);
274 return EXEC_SUCCESS;
275 }
276
RemoveScreen(ScreenId id)277 int32_t HgmCore::RemoveScreen(ScreenId id)
278 {
279 std::lock_guard<std::mutex> lock(listMutex_);
280 // delete a screen during a hotplug event
281 HGM_LOGD("HgmCore deleting the screen : " PUBU64 "", id);
282 for (auto screen = screenIds_.begin(); screen != screenIds_.end(); ++screen) {
283 if (*screen == id) {
284 screenIds_.erase(screen);
285 break;
286 }
287 }
288 for (auto screen = screenList_.begin(); screen != screenList_.end(); ++screen) {
289 if ((*screen)->GetId() == id) {
290 screenList_.erase(screen);
291 break;
292 }
293 }
294 return EXEC_SUCCESS;
295 }
296
AddScreenInfo(ScreenId id,int32_t width,int32_t height,uint32_t rate,int32_t mode)297 int32_t HgmCore::AddScreenInfo(ScreenId id, int32_t width, int32_t height, uint32_t rate, int32_t mode)
298 {
299 // add a supported screen mode to the screen
300 auto screen = GetScreen(id);
301 if (!screen) {
302 HGM_LOGW("HgmCore failed to get screen of : " PUBU64 "", id);
303 return HGM_NO_SCREEN;
304 }
305
306 if (screen->AddScreenModeInfo(width, height, rate, mode) == EXEC_SUCCESS) {
307 return EXEC_SUCCESS;
308 }
309
310 HGM_LOGW("HgmCore failed to add screen mode info of screen : " PUBU64 "", id);
311 return HGM_SCREEN_PARAM_ERROR;
312 }
313
RefreshBundleName(std::string name)314 int32_t HgmCore::RefreshBundleName(std::string name)
315 {
316 if (name == currentBundleName_) {
317 return EXEC_SUCCESS;
318 }
319
320 currentBundleName_ = name;
321
322 if (customFrameRateMode_ == HGM_REFRESHRATE_MODE_AUTO) {
323 return EXEC_SUCCESS;
324 }
325
326 int resetResult = SetRefreshRateMode(customFrameRateMode_);
327 if (resetResult == EXEC_SUCCESS) {
328 HGM_LOGI("HgmCore reset current refreshrate mode: %{public}d due to bundlename: %{public}s",
329 customFrameRateMode_, currentBundleName_.c_str());
330 }
331 return EXEC_SUCCESS;
332 }
333
GetScreenCurrentRefreshRate(ScreenId id)334 uint32_t HgmCore::GetScreenCurrentRefreshRate(ScreenId id)
335 {
336 auto screen = GetScreen(id);
337 if (!screen) {
338 HGM_LOGW("HgmCore failed to find screen " PUBU64 "", id);
339 return static_cast<uint32_t>(EXEC_SUCCESS);
340 }
341
342 return screen->GetActiveRefreshRate();
343 }
344
GetScreen(ScreenId id) const345 sptr<HgmScreen> HgmCore::GetScreen(ScreenId id) const
346 {
347 std::lock_guard<std::mutex> lock(listMutex_);
348 for (auto screen = screenList_.begin(); screen != screenList_.end(); ++screen) {
349 if ((*screen)->GetId() == id) {
350 return *screen;
351 }
352 }
353
354 return nullptr;
355 }
356
GetScreenSupportedRefreshRates(ScreenId id)357 std::vector<uint32_t> HgmCore::GetScreenSupportedRefreshRates(ScreenId id)
358 {
359 auto screen = GetScreen(id);
360 if (!screen) {
361 HGM_LOGW("HgmCore failed to find screen " PUBU64 "", id);
362 return std::vector<uint32_t>(static_cast<uint32_t>(EXEC_SUCCESS));
363 }
364
365 auto supportedRates = screen->GetSupportedRates();
366 std::vector<uint32_t> retVec;
367 retVec.assign(supportedRates.begin(), supportedRates.end());
368 return retVec;
369 }
370
GetModesToApply()371 std::unique_ptr<std::unordered_map<ScreenId, int32_t>> HgmCore::GetModesToApply()
372 {
373 std::lock_guard<std::mutex> lock(modeListMutex_);
374 return std::move(modeListToApply_);
375 }
376
AddScreenProfile(ScreenId id,int32_t width,int32_t height,int32_t phyWidth,int32_t phyHeight)377 int32_t HgmCore::AddScreenProfile(ScreenId id, int32_t width, int32_t height, int32_t phyWidth, int32_t phyHeight)
378 {
379 return hgmFrameRateTool_->AddScreenProfile(id, width, height, phyWidth, phyHeight);
380 }
381
RemoveScreenProfile(ScreenId id)382 int32_t HgmCore::RemoveScreenProfile(ScreenId id)
383 {
384 return hgmFrameRateTool_->RemoveScreenProfile(id);
385 }
386
CalModifierPreferred(HgmModifierProfile & hgmModifierProfile) const387 int32_t HgmCore::CalModifierPreferred(HgmModifierProfile &hgmModifierProfile) const
388 {
389 return hgmFrameRateTool_->CalModifierPreferred(activeScreenId_, hgmModifierProfile, mParsedConfigData_);
390 }
391
SetActiveScreenId(ScreenId id)392 void HgmCore::SetActiveScreenId(ScreenId id)
393 {
394 activeScreenId_ = id;
395 }
396
397 } // namespace OHOS::Rosen
398