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 <algorithm>
19 #include <cstddef>
20 #include <cstdint>
21 #include <string>
22 #include <unistd.h>
23
24 #include "hgm_frame_rate_manager.h"
25 #include "hgm_config_callback_manager.h"
26 #include "hgm_log.h"
27 #include "vsync_generator.h"
28 #include "platform/common/rs_system_properties.h"
29 #include "parameters.h"
30 #include "frame_rate_report.h"
31 #include "sandbox_utils.h"
32
33 namespace OHOS::Rosen {
34 static std::map<uint32_t, int64_t> IDEAL_PERIOD = {
35 { 144, 6944444 },
36 { 120, 8333333 },
37 { 90, 11111111 },
38 { 80, 12500000 },
39 { 72, 13888888 },
40 { 60, 16666666 },
41 { 48, 20833333 },
42 { 45, 22222222 },
43 { 40, 25000000 },
44 { 36, 27777777 },
45 { 30, 33333333 },
46 { 24, 41666666 },
47 { 20, 50000000 },
48 { 15, 66666666 },
49 { 10, 100000000 },
50 };
51
Instance()52 HgmCore& HgmCore::Instance()
53 {
54 static HgmCore instance;
55 static std::mutex mtx;
56 if (instance.IsInit()) {
57 return instance;
58 }
59
60 std::lock_guard<std::mutex> lock(mtx);
61 if (instance.IsInit()) {
62 return instance;
63 }
64
65 if (instance.Init() == false) {
66 HGM_LOGI("HgmCore initialization failed");
67 }
68
69 return instance;
70 }
71
HgmCore()72 HgmCore::HgmCore()
73 {
74 HGM_LOGI("Construction of Hgmcore");
75 }
76
Init()77 bool HgmCore::Init()
78 {
79 if (!isEnabled_) {
80 HGM_LOGE("HgmCore Hgm is desactivated");
81 return false;
82 }
83
84 if (InitXmlConfig() != EXEC_SUCCESS) {
85 HGM_LOGE("HgmCore falied to parse");
86 return false;
87 }
88
89 // ensure that frameRateManager init after XML parsed.
90 hgmFrameRateMgr_ = std::make_unique<HgmFrameRateManager>();
91
92 auto newRateMode = static_cast<int32_t>(RSSystemProperties::GetHgmRefreshRateModesEnabled());
93 if (newRateMode == 0) {
94 HGM_LOGI("HgmCore No customer refreshrate mode found, set to xml default");
95 if (mPolicyConfigData_ == nullptr || !XMLParser::IsNumber(mPolicyConfigData_->defaultRefreshRateMode_)) {
96 HGM_LOGE("HgmCore failed to get parsed data");
97 } else {
98 customFrameRateMode_ = std::stoi(mPolicyConfigData_->defaultRefreshRateMode_);
99 }
100 } else {
101 HGM_LOGI("HgmCore No customer refreshrate mode found: %{public}d", newRateMode);
102 customFrameRateMode_ = newRateMode;
103 if (customFrameRateMode_ != HGM_REFRESHRATE_MODE_AUTO &&
104 mPolicyConfigData_ != nullptr && mPolicyConfigData_->xmlCompatibleMode_) {
105 customFrameRateMode_ = mPolicyConfigData_->SettingModeId2XmlModeId(customFrameRateMode_);
106 }
107 CheckCustomFrameRateModeValid();
108 }
109
110 SetLtpoConfig();
111
112 isInit_.store(true);
113 HGM_LOGI("HgmCore initialization success!!!");
114 return isInit_;
115 }
116
CheckCustomFrameRateModeValid()117 void HgmCore::CheckCustomFrameRateModeValid()
118 {
119 if (hgmFrameRateMgr_ == nullptr || mPolicyConfigData_ == nullptr) {
120 return;
121 }
122
123 auto curScreenStrategyId = hgmFrameRateMgr_->GetCurScreenStrategyId();
124 auto &screenConfigs = mPolicyConfigData_->screenConfigs_;
125 if (screenConfigs.find(curScreenStrategyId) == screenConfigs.end()) {
126 return;
127 }
128
129 auto &screenConfig = screenConfigs[curScreenStrategyId];
130 auto modeStr = std::to_string(customFrameRateMode_);
131 if (screenConfig.find(modeStr) != screenConfig.end() || screenConfig.empty()) {
132 return;
133 }
134
135 int32_t maxMode = HGM_REFRESHRATE_MODE_AUTO;
136 for (auto &[modeStr, _] : screenConfig) {
137 if (!XMLParser::IsNumber(modeStr)) {
138 continue;
139 }
140 auto mode = std::stoi(modeStr);
141 if (maxMode < mode) {
142 maxMode = mode;
143 }
144 }
145 HGM_LOGE("auto repair mode: %{public}d -> %{public}d", customFrameRateMode_, maxMode);
146 customFrameRateMode_ = maxMode;
147 }
148
InitXmlConfig()149 int32_t HgmCore::InitXmlConfig()
150 {
151 HGM_LOGD("HgmCore is parsing xml configuration");
152 if (!mParser_) {
153 mParser_ = std::make_unique<XMLParser>();
154 }
155
156 if (mParser_->LoadConfiguration(configFileProduct) != EXEC_SUCCESS) {
157 HGM_LOGW("HgmCore failed to load prod xml configuration file");
158 }
159 if (mParser_->Parse() != EXEC_SUCCESS) {
160 HGM_LOGW("HgmCore failed to parse prod xml configuration");
161 }
162
163 if (!mPolicyConfigData_) {
164 mPolicyConfigData_ = mParser_->GetParsedData();
165 }
166
167 return EXEC_SUCCESS;
168 }
169
SetLtpoConfig()170 void HgmCore::SetLtpoConfig()
171 {
172 if ((hgmFrameRateMgr_ == nullptr) || (mPolicyConfigData_ == nullptr)) {
173 return;
174 }
175 auto curScreenStrategyId = hgmFrameRateMgr_->GetCurScreenStrategyId();
176 if (mPolicyConfigData_->screenConfigs_.count(curScreenStrategyId) == 0 ||
177 mPolicyConfigData_->screenConfigs_[curScreenStrategyId].count(std::to_string(customFrameRateMode_)) == 0) {
178 return;
179 }
180 auto curScreenSetting =
181 mPolicyConfigData_->screenConfigs_[curScreenStrategyId][std::to_string(customFrameRateMode_)];
182 if (curScreenSetting.ltpoConfig.find("switch") != curScreenSetting.ltpoConfig.end() &&
183 XMLParser::IsNumber(curScreenSetting.ltpoConfig["switch"])) {
184 ltpoEnabled_ = std::stoi(curScreenSetting.ltpoConfig["switch"]);
185 } else {
186 ltpoEnabled_ = 0;
187 HGM_LOGW("HgmCore failed to find switch strategy for LTPO");
188 }
189
190 if (curScreenSetting.ltpoConfig.find("maxTE") != curScreenSetting.ltpoConfig.end()) {
191 maxTE_ = std::stoul(curScreenSetting.ltpoConfig["maxTE"]);
192 } else {
193 maxTE_ = 0;
194 HGM_LOGW("HgmCore failed to find TE strategy for LTPO");
195 }
196
197 if (curScreenSetting.ltpoConfig.find("alignRate") != curScreenSetting.ltpoConfig.end()) {
198 alignRate_ = std::stoul(curScreenSetting.ltpoConfig["alignRate"]);
199 } else {
200 alignRate_ = 0;
201 HGM_LOGW("HgmCore failed to find alignRate strategy for LTPO");
202 }
203
204 if (curScreenSetting.ltpoConfig.find("pipelineOffsetPulseNum") != curScreenSetting.ltpoConfig.end() &&
205 XMLParser::IsNumber(curScreenSetting.ltpoConfig["pipelineOffsetPulseNum"])) {
206 pipelineOffsetPulseNum_ = std::stoi(curScreenSetting.ltpoConfig["pipelineOffsetPulseNum"]);
207 CreateVSyncGenerator()->SetVSyncPhaseByPulseNum(pipelineOffsetPulseNum_);
208 } else {
209 pipelineOffsetPulseNum_ = 0;
210 HGM_LOGW("HgmCore failed to find pipelineOffset strategy for LTPO");
211 }
212
213 SetScreenConstraintConfig();
214 HGM_LOGI("HgmCore LTPO strategy ltpoEnabled: %{public}d, maxTE: %{public}d, alignRate: %{public}d, " \
215 "pipelineOffsetPulseNum: %{public}d, vBlankIdleCorrectSwitch: %{public}d, lowRateToHighQuickSwitch: %{public}d",
216 ltpoEnabled_, maxTE_, alignRate_, pipelineOffsetPulseNum_, vBlankIdleCorrectSwitch_, lowRateToHighQuickSwitch_);
217 }
218
SetScreenConstraintConfig()219 void HgmCore::SetScreenConstraintConfig()
220 {
221 auto curScreenStrategyId = hgmFrameRateMgr_->GetCurScreenStrategyId();
222 if (mPolicyConfigData_->screenConfigs_.count(curScreenStrategyId) == 0 ||
223 mPolicyConfigData_->screenConfigs_[curScreenStrategyId].count(std::to_string(customFrameRateMode_)) == 0) {
224 return;
225 }
226 auto curScreenSetting =
227 mPolicyConfigData_->screenConfigs_[curScreenStrategyId][std::to_string(customFrameRateMode_)];
228 if (curScreenSetting.ltpoConfig.find("vBlankIdleCorrectSwitch") != curScreenSetting.ltpoConfig.end() &&
229 XMLParser::IsNumber(curScreenSetting.ltpoConfig["vBlankIdleCorrectSwitch"])) {
230 vBlankIdleCorrectSwitch_ = std::stoi(curScreenSetting.ltpoConfig["vBlankIdleCorrectSwitch"]);
231 } else {
232 vBlankIdleCorrectSwitch_ = 0;
233 HGM_LOGW("HgmCore failed to find vBlankIdleCorrectSwitch strategy for LTPO");
234 }
235
236 if (curScreenSetting.ltpoConfig.find("lowRateToHighQuickSwitch") != curScreenSetting.ltpoConfig.end() &&
237 XMLParser::IsNumber(curScreenSetting.ltpoConfig["lowRateToHighQuickSwitch"])) {
238 lowRateToHighQuickSwitch_ = std::stoi(curScreenSetting.ltpoConfig["lowRateToHighQuickSwitch"]);
239 } else {
240 lowRateToHighQuickSwitch_ = 0;
241 HGM_LOGW("HgmCore failed to find lowRateToHighQuickSwitch strategy for LTPO");
242 }
243 }
244
RegisterRefreshRateModeChangeCallback(const RefreshRateModeChangeCallback & callback)245 void HgmCore::RegisterRefreshRateModeChangeCallback(const RefreshRateModeChangeCallback& callback)
246 {
247 refreshRateModeChangeCallback_ = callback;
248 if (refreshRateModeChangeCallback_ != nullptr) {
249 auto refreshRateModeName = GetCurrentRefreshRateModeName();
250 refreshRateModeChangeCallback_(refreshRateModeName);
251 }
252 }
253
SetCustomRateMode(int32_t mode)254 int32_t HgmCore::SetCustomRateMode(int32_t mode)
255 {
256 customFrameRateMode_ = mode;
257 return EXEC_SUCCESS;
258 }
259
RegisterRefreshRateUpdateCallback(const RefreshRateUpdateCallback & callback)260 void HgmCore::RegisterRefreshRateUpdateCallback(const RefreshRateUpdateCallback& callback)
261 {
262 ScreenId screenId = HgmCore::Instance().GetActiveScreenId();
263 uint32_t refreshRate = HgmCore::Instance().GetScreenCurrentRefreshRate(screenId);
264 refreshRateUpdateCallback_ = callback;
265 if (refreshRateUpdateCallback_ != nullptr) {
266 refreshRateUpdateCallback_(refreshRate);
267 }
268 }
269
SetScreenRefreshRate(ScreenId id,int32_t sceneId,int32_t rate)270 int32_t HgmCore::SetScreenRefreshRate(ScreenId id, int32_t sceneId, int32_t rate)
271 {
272 // set the screen to the desired refreshrate
273 HGM_LOGD("HgmCore setting screen " PUBU64 " to the rate of %{public}d", id, rate);
274 auto screen = GetScreen(id);
275 if (!screen) {
276 HGM_LOGW("HgmCore failed to get screen of : " PUBU64 "", id);
277 return HGM_ERROR;
278 }
279
280 if (rate <= 0) {
281 HGM_LOGW("HgmCore refuse an illegal framerate: %{public}d", rate);
282 return HGM_ERROR;
283 }
284 sceneId = static_cast<int32_t>(screenSceneSet_.size());
285 int32_t modeToSwitch = screen->SetActiveRefreshRate(sceneId, static_cast<uint32_t>(rate));
286 if (modeToSwitch < 0) {
287 return modeToSwitch;
288 }
289
290 std::lock_guard<std::mutex> lock(modeListMutex_);
291
292 // the rate is accepted and passed to a list, will be applied by hardwarethread before sending the composition
293 HGM_LOGI("HgmCore the rate of %{public}d is accepted, the target mode is %{public}d", rate, modeToSwitch);
294 if (modeListToApply_ == nullptr) {
295 HGM_LOGD("HgmCore modeListToApply_ is invalid, buiding a new mode list");
296 modeListToApply_ = std::make_unique<std::unordered_map<ScreenId, int32_t>>();
297 }
298 auto modeList = modeListToApply_.get();
299 (*modeList)[id] = modeToSwitch;
300
301 if (refreshRateUpdateCallback_) {
302 refreshRateUpdateCallback_(rate);
303 HGM_LOGD("refresh rate changed, notify to app");
304 }
305 return modeToSwitch;
306 }
307
SetRateAndResolution(ScreenId id,int32_t sceneId,int32_t rate,int32_t width,int32_t height)308 int32_t HgmCore::SetRateAndResolution(ScreenId id, int32_t sceneId, int32_t rate, int32_t width, int32_t height)
309 {
310 // reserved
311 return HGM_ERROR;
312 }
313
SetRefreshRateMode(int32_t refreshRateMode)314 int32_t HgmCore::SetRefreshRateMode(int32_t refreshRateMode)
315 {
316 // setting mode to xml modeid
317 if (refreshRateMode != HGM_REFRESHRATE_MODE_AUTO
318 && mPolicyConfigData_ != nullptr && mPolicyConfigData_->xmlCompatibleMode_) {
319 refreshRateMode = mPolicyConfigData_->SettingModeId2XmlModeId(refreshRateMode);
320 }
321 HGM_LOGD("HgmCore set refreshrate mode to : %{public}d", refreshRateMode);
322 // change refreshrate mode by setting application
323 if (SetCustomRateMode(refreshRateMode) != EXEC_SUCCESS) {
324 return HGM_ERROR;
325 }
326
327 hgmFrameRateMgr_->HandleRefreshRateMode(refreshRateMode);
328
329 auto refreshRateModeName = GetCurrentRefreshRateModeName();
330 if (refreshRateModeChangeCallback_ != nullptr) {
331 refreshRateModeChangeCallback_(refreshRateModeName);
332 }
333 HgmConfigCallbackManager::GetInstance()->SyncRefreshRateModeChangeCallback(refreshRateModeName);
334 return EXEC_SUCCESS;
335 }
336
NotifyScreenPowerStatus(ScreenId id,ScreenPowerStatus status)337 void HgmCore::NotifyScreenPowerStatus(ScreenId id, ScreenPowerStatus status)
338 {
339 if (hgmFrameRateMgr_ != nullptr) {
340 hgmFrameRateMgr_->HandleScreenPowerStatus(id, status);
341 }
342
343 if (refreshRateModeChangeCallback_ != nullptr) {
344 auto refreshRateModeName = GetCurrentRefreshRateModeName();
345 refreshRateModeChangeCallback_(refreshRateModeName);
346 }
347 }
348
AddScreen(ScreenId id,int32_t defaultMode,ScreenSize & screenSize)349 int32_t HgmCore::AddScreen(ScreenId id, int32_t defaultMode, ScreenSize& screenSize)
350 {
351 // add a physical screen to hgm during hotplug event
352 HGM_LOGI("HgmCore adding screen : " PUBI64 "", id);
353 bool removeId = std::any_of(screenIds_.begin(), screenIds_.end(),
354 [id](const ScreenId screen) { return screen == id; });
355 if (removeId) {
356 if (RemoveScreen(id) != EXEC_SUCCESS) {
357 HGM_LOGW("HgmCore failed to remove the existing screen, not adding : " PUBI64 "", id);
358 return HGM_BASE_REMOVE_FAILED;
359 }
360 }
361
362 sptr<HgmScreen> newScreen = new HgmScreen(id, defaultMode, screenSize);
363
364 std::lock_guard<std::mutex> lock(listMutex_);
365 screenList_.push_back(newScreen);
366 screenIds_.push_back(id);
367
368 int32_t screenNum = GetScreenListSize();
369 HGM_LOGI("HgmCore num of screen is %{public}d", screenNum);
370 return EXEC_SUCCESS;
371 }
372
RemoveScreen(ScreenId id)373 int32_t HgmCore::RemoveScreen(ScreenId id)
374 {
375 std::lock_guard<std::mutex> lock(listMutex_);
376 // delete a screen during a hotplug event
377 HGM_LOGD("HgmCore deleting the screen : " PUBU64 "", id);
378 for (auto screen = screenIds_.begin(); screen != screenIds_.end(); ++screen) {
379 if (*screen == id) {
380 screenIds_.erase(screen);
381 break;
382 }
383 }
384 for (auto screen = screenList_.begin(); screen != screenList_.end(); ++screen) {
385 if ((*screen)->GetId() == id) {
386 screenList_.erase(screen);
387 break;
388 }
389 }
390 return EXEC_SUCCESS;
391 }
392
AddScreenInfo(ScreenId id,int32_t width,int32_t height,uint32_t rate,int32_t mode)393 int32_t HgmCore::AddScreenInfo(ScreenId id, int32_t width, int32_t height, uint32_t rate, int32_t mode)
394 {
395 // add a supported screen mode to the screen
396 auto screen = GetScreen(id);
397 if (!screen) {
398 HGM_LOGW("HgmCore failed to get screen of : " PUBU64 "", id);
399 return HGM_NO_SCREEN;
400 }
401
402 if (screen->AddScreenModeInfo(width, height, rate, mode) == EXEC_SUCCESS) {
403 return EXEC_SUCCESS;
404 }
405
406 HGM_LOGW("HgmCore failed to add screen mode info of screen : " PUBU64 "", id);
407 return HGM_SCREEN_PARAM_ERROR;
408 }
409
RefreshBundleName(const std::string & name)410 int32_t HgmCore::RefreshBundleName(const std::string& name)
411 {
412 if (name == currentBundleName_) {
413 return EXEC_SUCCESS;
414 }
415
416 currentBundleName_ = name;
417
418 if (customFrameRateMode_ == HGM_REFRESHRATE_MODE_AUTO) {
419 return EXEC_SUCCESS;
420 }
421
422 int resetResult = SetRefreshRateMode(customFrameRateMode_);
423 if (resetResult == EXEC_SUCCESS) {
424 HGM_LOGI("HgmCore reset current refreshrate mode: %{public}d due to bundlename: %{public}s",
425 customFrameRateMode_, currentBundleName_.c_str());
426 }
427 return EXEC_SUCCESS;
428 }
429
GetScreenCurrentRefreshRate(ScreenId id) const430 uint32_t HgmCore::GetScreenCurrentRefreshRate(ScreenId id) const
431 {
432 auto screen = GetScreen(id);
433 if (!screen) {
434 HGM_LOGW("HgmCore failed to find screen " PUBU64 "", id);
435 return static_cast<uint32_t>(EXEC_SUCCESS);
436 }
437
438 return screen->GetActiveRefreshRate();
439 }
440
GetCurrentRefreshRateMode() const441 int32_t HgmCore::GetCurrentRefreshRateMode() const
442 {
443 if (customFrameRateMode_ != HGM_REFRESHRATE_MODE_AUTO
444 && mPolicyConfigData_ != nullptr && mPolicyConfigData_->xmlCompatibleMode_) {
445 return mPolicyConfigData_->XmlModeId2SettingModeId(customFrameRateMode_);
446 }
447 return customFrameRateMode_;
448 }
449
GetCurrentRefreshRateModeName() const450 int32_t HgmCore::GetCurrentRefreshRateModeName() const
451 {
452 if (mPolicyConfigData_ != nullptr && mPolicyConfigData_->xmlCompatibleMode_) {
453 return mPolicyConfigData_->GetRefreshRateModeName(customFrameRateMode_);
454 }
455 std::map<int32_t, int32_t> modeIdRateMap = {{-1, -1}, {1, 60}, {2, 90}, {3, 120}};
456 if (modeIdRateMap.find(customFrameRateMode_) != modeIdRateMap.end()) {
457 return modeIdRateMap[customFrameRateMode_];
458 }
459 return customFrameRateMode_;
460 }
461
GetScreen(ScreenId id) const462 sptr<HgmScreen> HgmCore::GetScreen(ScreenId id) const
463 {
464 std::lock_guard<std::mutex> lock(listMutex_);
465 for (auto screen = screenList_.begin(); screen != screenList_.end(); ++screen) {
466 if ((*screen)->GetId() == id) {
467 return *screen;
468 }
469 }
470
471 return nullptr;
472 }
473
GetScreenSupportedRefreshRates(ScreenId id)474 std::vector<uint32_t> HgmCore::GetScreenSupportedRefreshRates(ScreenId id)
475 {
476 auto screen = GetScreen(id);
477 if (!screen) {
478 HGM_LOGW("HgmCore failed to find screen " PUBU64 "", id);
479 return std::vector<uint32_t>(static_cast<uint32_t>(EXEC_SUCCESS));
480 }
481
482 auto supportedRates = screen->GetSupportedRates();
483 std::vector<uint32_t> retVec;
484 retVec.assign(supportedRates.begin(), supportedRates.end());
485 return retVec;
486 }
487
GetScreenComponentRefreshRates(ScreenId id)488 std::vector<int32_t> HgmCore::GetScreenComponentRefreshRates(ScreenId id)
489 {
490 if (!mPolicyConfigData_) {
491 HGM_LOGW("HgmCore no parsed component data, returning default value");
492 return std::vector<int32_t>(static_cast<uint32_t>(EXEC_SUCCESS));
493 }
494
495 std::vector<int32_t> retVec;
496 for (const auto& [rate, _] : mPolicyConfigData_->refreshRateForSettings_) {
497 retVec.emplace_back(rate);
498 HGM_LOGE("HgmCore Adding component rate: %{public}d", rate);
499 }
500 return retVec;
501 }
502
GetModesToApply()503 std::unique_ptr<std::unordered_map<ScreenId, int32_t>> HgmCore::GetModesToApply()
504 {
505 std::lock_guard<std::mutex> lock(modeListMutex_);
506 return std::move(modeListToApply_);
507 }
508
SetActiveScreenId(ScreenId id)509 void HgmCore::SetActiveScreenId(ScreenId id)
510 {
511 activeScreenId_ = id;
512 }
513
GetActiveScreen() const514 sptr<HgmScreen> HgmCore::GetActiveScreen() const
515 {
516 if (activeScreenId_ == INVALID_SCREEN_ID) {
517 HGM_LOGE("HgmScreen activeScreenId_ noset");
518 return nullptr;
519 }
520 return GetScreen(activeScreenId_);
521 }
522
GetIdealPeriod(uint32_t rate)523 int64_t HgmCore::GetIdealPeriod(uint32_t rate)
524 {
525 if (IDEAL_PERIOD.count(rate)) {
526 return IDEAL_PERIOD[rate];
527 }
528 return 0;
529 }
530 } // namespace OHOS::Rosen
531