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 isDelayMode_ = RSSystemProperties::IsPhoneType() || RSSystemProperties::IsTabletType();
114 HGM_LOGI("HgmCore initialization success!!! delayMode: %{public}d", isDelayMode_);
115 return isInit_;
116 }
117
CheckCustomFrameRateModeValid()118 void HgmCore::CheckCustomFrameRateModeValid()
119 {
120 if (hgmFrameRateMgr_ == nullptr || mPolicyConfigData_ == nullptr) {
121 return;
122 }
123
124 auto curScreenStrategyId = hgmFrameRateMgr_->GetCurScreenStrategyId();
125 auto &screenConfigs = mPolicyConfigData_->screenConfigs_;
126 if (screenConfigs.find(curScreenStrategyId) == screenConfigs.end()) {
127 return;
128 }
129
130 auto &screenConfig = screenConfigs[curScreenStrategyId];
131 auto modeStr = std::to_string(customFrameRateMode_);
132 if (screenConfig.find(modeStr) != screenConfig.end() || screenConfig.empty()) {
133 return;
134 }
135
136 int32_t maxMode = HGM_REFRESHRATE_MODE_AUTO;
137 for (auto &[modeStr, _] : screenConfig) {
138 if (!XMLParser::IsNumber(modeStr)) {
139 continue;
140 }
141 auto mode = std::stoi(modeStr);
142 if (maxMode < mode) {
143 maxMode = mode;
144 }
145 }
146 HGM_LOGE("auto repair mode: %{public}d -> %{public}d", customFrameRateMode_, maxMode);
147 customFrameRateMode_ = maxMode;
148 }
149
InitXmlConfig()150 int32_t HgmCore::InitXmlConfig()
151 {
152 HGM_LOGD("HgmCore is parsing xml configuration");
153 if (!mParser_) {
154 mParser_ = std::make_unique<XMLParser>();
155 }
156
157 if (mParser_->LoadConfiguration(configFileProduct) != EXEC_SUCCESS) {
158 HGM_LOGW("HgmCore failed to load prod xml configuration file");
159 }
160 if (mParser_->Parse() != EXEC_SUCCESS) {
161 HGM_LOGW("HgmCore failed to parse prod xml configuration");
162 }
163
164 if (!mPolicyConfigData_) {
165 mPolicyConfigData_ = mParser_->GetParsedData();
166 }
167
168 return EXEC_SUCCESS;
169 }
170
SetLtpoConfig()171 void HgmCore::SetLtpoConfig()
172 {
173 if ((hgmFrameRateMgr_ == nullptr) || (mPolicyConfigData_ == nullptr)) {
174 return;
175 }
176 auto curScreenStrategyId = hgmFrameRateMgr_->GetCurScreenStrategyId();
177 if (mPolicyConfigData_->screenConfigs_.count(curScreenStrategyId) == 0 ||
178 mPolicyConfigData_->screenConfigs_[curScreenStrategyId].count(std::to_string(customFrameRateMode_)) == 0) {
179 return;
180 }
181 auto curScreenSetting =
182 mPolicyConfigData_->screenConfigs_[curScreenStrategyId][std::to_string(customFrameRateMode_)];
183 if (curScreenSetting.ltpoConfig.find("switch") != curScreenSetting.ltpoConfig.end() &&
184 XMLParser::IsNumber(curScreenSetting.ltpoConfig["switch"])) {
185 ltpoEnabled_ = std::stoi(curScreenSetting.ltpoConfig["switch"]);
186 } else {
187 ltpoEnabled_ = 0;
188 HGM_LOGW("HgmCore failed to find switch strategy for LTPO");
189 }
190
191 if (curScreenSetting.ltpoConfig.find("maxTE") != curScreenSetting.ltpoConfig.end()) {
192 maxTE_ = std::stoul(curScreenSetting.ltpoConfig["maxTE"]);
193 } else {
194 maxTE_ = 0;
195 HGM_LOGW("HgmCore failed to find TE strategy for LTPO");
196 }
197
198 if (curScreenSetting.ltpoConfig.find("alignRate") != curScreenSetting.ltpoConfig.end()) {
199 alignRate_ = std::stoul(curScreenSetting.ltpoConfig["alignRate"]);
200 } else {
201 alignRate_ = 0;
202 HGM_LOGW("HgmCore failed to find alignRate strategy for LTPO");
203 }
204
205 if (curScreenSetting.ltpoConfig.find("pipelineOffsetPulseNum") != curScreenSetting.ltpoConfig.end() &&
206 XMLParser::IsNumber(curScreenSetting.ltpoConfig["pipelineOffsetPulseNum"])) {
207 pipelineOffsetPulseNum_ = std::stoi(curScreenSetting.ltpoConfig["pipelineOffsetPulseNum"]);
208 CreateVSyncGenerator()->SetVSyncPhaseByPulseNum(pipelineOffsetPulseNum_);
209 } else {
210 pipelineOffsetPulseNum_ = 0;
211 HGM_LOGW("HgmCore failed to find pipelineOffset strategy for LTPO");
212 }
213
214 SetScreenConstraintConfig();
215 HGM_LOGI("HgmCore LTPO strategy ltpoEnabled: %{public}d, maxTE: %{public}d, alignRate: %{public}d, " \
216 "pipelineOffsetPulseNum: %{public}d, vBlankIdleCorrectSwitch: %{public}d, lowRateToHighQuickSwitch: %{public}d",
217 ltpoEnabled_, maxTE_, alignRate_, pipelineOffsetPulseNum_, vBlankIdleCorrectSwitch_, lowRateToHighQuickSwitch_);
218 }
219
SetScreenConstraintConfig()220 void HgmCore::SetScreenConstraintConfig()
221 {
222 auto curScreenStrategyId = hgmFrameRateMgr_->GetCurScreenStrategyId();
223 if (mPolicyConfigData_->screenConfigs_.count(curScreenStrategyId) == 0 ||
224 mPolicyConfigData_->screenConfigs_[curScreenStrategyId].count(std::to_string(customFrameRateMode_)) == 0) {
225 return;
226 }
227 auto curScreenSetting =
228 mPolicyConfigData_->screenConfigs_[curScreenStrategyId][std::to_string(customFrameRateMode_)];
229 if (curScreenSetting.ltpoConfig.find("vBlankIdleCorrectSwitch") != curScreenSetting.ltpoConfig.end() &&
230 XMLParser::IsNumber(curScreenSetting.ltpoConfig["vBlankIdleCorrectSwitch"])) {
231 vBlankIdleCorrectSwitch_ = std::stoi(curScreenSetting.ltpoConfig["vBlankIdleCorrectSwitch"]);
232 } else {
233 vBlankIdleCorrectSwitch_ = 0;
234 HGM_LOGW("HgmCore failed to find vBlankIdleCorrectSwitch strategy for LTPO");
235 }
236
237 if (curScreenSetting.ltpoConfig.find("lowRateToHighQuickSwitch") != curScreenSetting.ltpoConfig.end() &&
238 XMLParser::IsNumber(curScreenSetting.ltpoConfig["lowRateToHighQuickSwitch"])) {
239 lowRateToHighQuickSwitch_ = std::stoi(curScreenSetting.ltpoConfig["lowRateToHighQuickSwitch"]);
240 } else {
241 lowRateToHighQuickSwitch_ = 0;
242 HGM_LOGW("HgmCore failed to find lowRateToHighQuickSwitch strategy for LTPO");
243 }
244 }
245
RegisterRefreshRateModeChangeCallback(const RefreshRateModeChangeCallback & callback)246 void HgmCore::RegisterRefreshRateModeChangeCallback(const RefreshRateModeChangeCallback& callback)
247 {
248 refreshRateModeChangeCallback_ = callback;
249 if (refreshRateModeChangeCallback_ != nullptr) {
250 auto refreshRateModeName = GetCurrentRefreshRateModeName();
251 refreshRateModeChangeCallback_(refreshRateModeName);
252 }
253 }
254
SetCustomRateMode(int32_t mode)255 int32_t HgmCore::SetCustomRateMode(int32_t mode)
256 {
257 customFrameRateMode_ = mode;
258 return EXEC_SUCCESS;
259 }
260
RegisterRefreshRateUpdateCallback(const RefreshRateUpdateCallback & callback)261 void HgmCore::RegisterRefreshRateUpdateCallback(const RefreshRateUpdateCallback& callback)
262 {
263 ScreenId screenId = HgmCore::Instance().GetActiveScreenId();
264 uint32_t refreshRate = HgmCore::Instance().GetScreenCurrentRefreshRate(screenId);
265 refreshRateUpdateCallback_ = callback;
266 if (refreshRateUpdateCallback_ != nullptr) {
267 refreshRateUpdateCallback_(refreshRate);
268 }
269 }
270
SetScreenRefreshRate(ScreenId id,int32_t sceneId,int32_t rate)271 int32_t HgmCore::SetScreenRefreshRate(ScreenId id, int32_t sceneId, int32_t rate)
272 {
273 // set the screen to the desired refreshrate
274 HGM_LOGD("HgmCore setting screen " PUBU64 " to the rate of %{public}d", id, rate);
275 auto screen = GetScreen(id);
276 if (!screen) {
277 HGM_LOGW("HgmCore failed to get screen of : " PUBU64 "", id);
278 return HGM_ERROR;
279 }
280
281 if (rate <= 0) {
282 HGM_LOGW("HgmCore refuse an illegal framerate: %{public}d", rate);
283 return HGM_ERROR;
284 }
285 sceneId = static_cast<int32_t>(screenSceneSet_.size());
286 int32_t modeToSwitch = screen->SetActiveRefreshRate(sceneId, static_cast<uint32_t>(rate));
287 if (modeToSwitch < 0) {
288 return modeToSwitch;
289 }
290
291 std::lock_guard<std::mutex> lock(modeListMutex_);
292
293 // the rate is accepted and passed to a list, will be applied by hardwarethread before sending the composition
294 HGM_LOGI("HgmCore the rate of %{public}d is accepted, the target mode is %{public}d", rate, modeToSwitch);
295 if (modeListToApply_ == nullptr) {
296 HGM_LOGD("HgmCore modeListToApply_ is invalid, buiding a new mode list");
297 modeListToApply_ = std::make_unique<std::unordered_map<ScreenId, int32_t>>();
298 }
299 auto modeList = modeListToApply_.get();
300 (*modeList)[id] = modeToSwitch;
301
302 if (refreshRateUpdateCallback_) {
303 refreshRateUpdateCallback_(rate);
304 HGM_LOGD("refresh rate changed, notify to app");
305 }
306 return modeToSwitch;
307 }
308
SetRateAndResolution(ScreenId id,int32_t sceneId,int32_t rate,int32_t width,int32_t height)309 int32_t HgmCore::SetRateAndResolution(ScreenId id, int32_t sceneId, int32_t rate, int32_t width, int32_t height)
310 {
311 // reserved
312 return HGM_ERROR;
313 }
314
SetRefreshRateMode(int32_t refreshRateMode)315 int32_t HgmCore::SetRefreshRateMode(int32_t refreshRateMode)
316 {
317 // setting mode to xml modeid
318 if (refreshRateMode != HGM_REFRESHRATE_MODE_AUTO
319 && mPolicyConfigData_ != nullptr && mPolicyConfigData_->xmlCompatibleMode_) {
320 refreshRateMode = mPolicyConfigData_->SettingModeId2XmlModeId(refreshRateMode);
321 }
322 HGM_LOGD("HgmCore set refreshrate mode to : %{public}d", refreshRateMode);
323 // change refreshrate mode by setting application
324 if (SetCustomRateMode(refreshRateMode) != EXEC_SUCCESS) {
325 return HGM_ERROR;
326 }
327
328 hgmFrameRateMgr_->HandleRefreshRateMode(refreshRateMode);
329
330 auto refreshRateModeName = GetCurrentRefreshRateModeName();
331 if (refreshRateModeChangeCallback_ != nullptr) {
332 refreshRateModeChangeCallback_(refreshRateModeName);
333 }
334 HgmConfigCallbackManager::GetInstance()->SyncRefreshRateModeChangeCallback(refreshRateModeName);
335 return EXEC_SUCCESS;
336 }
337
NotifyScreenPowerStatus(ScreenId id,ScreenPowerStatus status)338 void HgmCore::NotifyScreenPowerStatus(ScreenId id, ScreenPowerStatus status)
339 {
340 if (hgmFrameRateMgr_ != nullptr) {
341 hgmFrameRateMgr_->HandleScreenPowerStatus(id, status);
342 }
343
344 if (refreshRateModeChangeCallback_ != nullptr) {
345 auto refreshRateModeName = GetCurrentRefreshRateModeName();
346 refreshRateModeChangeCallback_(refreshRateModeName);
347 }
348 }
349
AddScreen(ScreenId id,int32_t defaultMode,ScreenSize & screenSize)350 int32_t HgmCore::AddScreen(ScreenId id, int32_t defaultMode, ScreenSize& screenSize)
351 {
352 // add a physical screen to hgm during hotplug event
353 HGM_LOGI("HgmCore adding screen : " PUBI64 "", id);
354 bool removeId = std::any_of(screenIds_.begin(), screenIds_.end(),
355 [id](const ScreenId screen) { return screen == id; });
356 if (removeId) {
357 if (RemoveScreen(id) != EXEC_SUCCESS) {
358 HGM_LOGW("HgmCore failed to remove the existing screen, not adding : " PUBI64 "", id);
359 return HGM_BASE_REMOVE_FAILED;
360 }
361 }
362
363 sptr<HgmScreen> newScreen = new HgmScreen(id, defaultMode, screenSize);
364
365 std::lock_guard<std::mutex> lock(listMutex_);
366 screenList_.push_back(newScreen);
367 screenIds_.push_back(id);
368
369 int32_t screenNum = GetScreenListSize();
370 HGM_LOGI("HgmCore num of screen is %{public}d", screenNum);
371 return EXEC_SUCCESS;
372 }
373
RemoveScreen(ScreenId id)374 int32_t HgmCore::RemoveScreen(ScreenId id)
375 {
376 std::lock_guard<std::mutex> lock(listMutex_);
377 // delete a screen during a hotplug event
378 HGM_LOGD("HgmCore deleting the screen : " PUBU64 "", id);
379 for (auto screen = screenIds_.begin(); screen != screenIds_.end(); ++screen) {
380 if (*screen == id) {
381 screenIds_.erase(screen);
382 break;
383 }
384 }
385 for (auto screen = screenList_.begin(); screen != screenList_.end(); ++screen) {
386 if ((*screen)->GetId() == id) {
387 screenList_.erase(screen);
388 break;
389 }
390 }
391 return EXEC_SUCCESS;
392 }
393
AddScreenInfo(ScreenId id,int32_t width,int32_t height,uint32_t rate,int32_t mode)394 int32_t HgmCore::AddScreenInfo(ScreenId id, int32_t width, int32_t height, uint32_t rate, int32_t mode)
395 {
396 // add a supported screen mode to the screen
397 auto screen = GetScreen(id);
398 if (!screen) {
399 HGM_LOGW("HgmCore failed to get screen of : " PUBU64 "", id);
400 return HGM_NO_SCREEN;
401 }
402
403 if (screen->AddScreenModeInfo(width, height, rate, mode) == EXEC_SUCCESS) {
404 return EXEC_SUCCESS;
405 }
406
407 HGM_LOGW("HgmCore failed to add screen mode info of screen : " PUBU64 "", id);
408 return HGM_SCREEN_PARAM_ERROR;
409 }
410
RefreshBundleName(const std::string & name)411 int32_t HgmCore::RefreshBundleName(const std::string& name)
412 {
413 if (name == currentBundleName_) {
414 return EXEC_SUCCESS;
415 }
416
417 currentBundleName_ = name;
418
419 if (customFrameRateMode_ == HGM_REFRESHRATE_MODE_AUTO) {
420 return EXEC_SUCCESS;
421 }
422
423 int resetResult = SetRefreshRateMode(customFrameRateMode_);
424 if (resetResult == EXEC_SUCCESS) {
425 HGM_LOGI("HgmCore reset current refreshrate mode: %{public}d due to bundlename: %{public}s",
426 customFrameRateMode_, currentBundleName_.c_str());
427 }
428 return EXEC_SUCCESS;
429 }
430
GetScreenCurrentRefreshRate(ScreenId id) const431 uint32_t HgmCore::GetScreenCurrentRefreshRate(ScreenId id) const
432 {
433 auto screen = GetScreen(id);
434 if (!screen) {
435 HGM_LOGW("HgmCore failed to find screen " PUBU64 "", id);
436 return static_cast<uint32_t>(EXEC_SUCCESS);
437 }
438
439 return screen->GetActiveRefreshRate();
440 }
441
GetCurrentRefreshRateMode() const442 int32_t HgmCore::GetCurrentRefreshRateMode() const
443 {
444 if (customFrameRateMode_ != HGM_REFRESHRATE_MODE_AUTO
445 && mPolicyConfigData_ != nullptr && mPolicyConfigData_->xmlCompatibleMode_) {
446 return mPolicyConfigData_->XmlModeId2SettingModeId(customFrameRateMode_);
447 }
448 return customFrameRateMode_;
449 }
450
GetCurrentRefreshRateModeName() const451 int32_t HgmCore::GetCurrentRefreshRateModeName() const
452 {
453 if (mPolicyConfigData_ != nullptr && mPolicyConfigData_->xmlCompatibleMode_) {
454 return mPolicyConfigData_->GetRefreshRateModeName(customFrameRateMode_);
455 }
456 std::map<int32_t, int32_t> modeIdRateMap = {{-1, -1}, {1, 60}, {2, 90}, {3, 120}};
457 if (modeIdRateMap.find(customFrameRateMode_) != modeIdRateMap.end()) {
458 return modeIdRateMap[customFrameRateMode_];
459 }
460 return customFrameRateMode_;
461 }
462
GetScreen(ScreenId id) const463 sptr<HgmScreen> HgmCore::GetScreen(ScreenId id) const
464 {
465 std::lock_guard<std::mutex> lock(listMutex_);
466 for (auto screen = screenList_.begin(); screen != screenList_.end(); ++screen) {
467 if ((*screen)->GetId() == id) {
468 return *screen;
469 }
470 }
471
472 return nullptr;
473 }
474
GetScreenSupportedRefreshRates(ScreenId id)475 std::vector<uint32_t> HgmCore::GetScreenSupportedRefreshRates(ScreenId id)
476 {
477 HgmTaskHandleThread::Instance().DetectMultiThreadingCalls();
478 auto screen = GetScreen(id);
479 if (!screen) {
480 HGM_LOGW("HgmCore failed to find screen " PUBU64 "", id);
481 return std::vector<uint32_t>(static_cast<uint32_t>(EXEC_SUCCESS));
482 }
483
484 auto supportedRates = screen->GetSupportedRates();
485 std::vector<uint32_t> retVec;
486 retVec.assign(supportedRates.begin(), supportedRates.end());
487 return retVec;
488 }
489
GetScreenComponentRefreshRates(ScreenId id)490 std::vector<int32_t> HgmCore::GetScreenComponentRefreshRates(ScreenId id)
491 {
492 if (!mPolicyConfigData_) {
493 HGM_LOGW("HgmCore no parsed component data, returning default value");
494 return std::vector<int32_t>(static_cast<uint32_t>(EXEC_SUCCESS));
495 }
496
497 std::vector<int32_t> retVec;
498 for (const auto& [rate, _] : mPolicyConfigData_->refreshRateForSettings_) {
499 retVec.emplace_back(rate);
500 HGM_LOGE("HgmCore Adding component rate: %{public}d", rate);
501 }
502 return retVec;
503 }
504
GetModesToApply()505 std::unique_ptr<std::unordered_map<ScreenId, int32_t>> HgmCore::GetModesToApply()
506 {
507 std::lock_guard<std::mutex> lock(modeListMutex_);
508 return std::move(modeListToApply_);
509 }
510
SetActiveScreenId(ScreenId id)511 void HgmCore::SetActiveScreenId(ScreenId id)
512 {
513 activeScreenId_ = id;
514 }
515
GetActiveScreen() const516 sptr<HgmScreen> HgmCore::GetActiveScreen() const
517 {
518 if (activeScreenId_ == INVALID_SCREEN_ID) {
519 HGM_LOGE("HgmScreen activeScreenId_ noset");
520 return nullptr;
521 }
522 return GetScreen(activeScreenId_);
523 }
524
GetIdealPeriod(uint32_t rate)525 int64_t HgmCore::GetIdealPeriod(uint32_t rate)
526 {
527 if (IDEAL_PERIOD.count(rate)) {
528 return IDEAL_PERIOD[rate];
529 }
530 return 0;
531 }
532 } // namespace OHOS::Rosen
533