1 /*
2 * Copyright (c) 2025 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 "feature/hyper_graphic_manager/hgm_hardware_utils.h"
17
18 #include "common/rs_optional_trace.h"
19 #include "parameters.h"
20 #include "pipeline/hardware_thread/rs_hardware_thread.h"
21
22 namespace OHOS {
23 namespace Rosen {
24 namespace {
25 constexpr int64_t NS_MS_UNIT_CONVERSION = 1000000;
26 constexpr uint32_t DELAY_TIME_OFFSET = 100;
27 constexpr int32_t MAX_SETRATE_RETRY_COUNT = 20;
28 constexpr ScreenId MAX_HAL_DISPLAY_ID = 20;
29 }
30
ExecuteSwitchRefreshRate(const std::shared_ptr<HdiOutput> output,uint32_t refreshRate)31 void HgmHardwareUtils::ExecuteSwitchRefreshRate(
32 const std::shared_ptr<HdiOutput> output, uint32_t refreshRate)
33 {
34 static bool refreshRateSwitch = system::GetBoolParameter("persist.hgm.refreshrate.enabled", true);
35 if (!refreshRateSwitch) {
36 RS_LOGD("refreshRateSwitch is off, currRefreshRate is %{public}d", refreshRate);
37 return;
38 }
39
40 auto& hgmCore = OHOS::Rosen::HgmCore::Instance();
41 if (hgmCore.GetFrameRateMgr() == nullptr) {
42 RS_LOGD("FrameRateMgr is null");
43 return;
44 }
45 ScreenId id = output->GetScreenId();
46 auto& hardwareThread = RSHardwareThread::Instance();
47 auto screen = hgmCore.GetScreen(id);
48 if (!screen || !screen->GetSelfOwnedScreenFlag()) {
49 return;
50 }
51 auto screenRefreshRateImme = hgmCore.GetScreenRefreshRateImme();
52 if (screenRefreshRateImme > 0) {
53 RS_LOGD("ExecuteSwitchRefreshRate:rate change: %{public}u -> %{public}u", refreshRate, screenRefreshRateImme);
54 refreshRate = screenRefreshRateImme;
55 }
56 ScreenId curScreenId = hgmCore.GetFrameRateMgr()->GetCurScreenId();
57 ScreenId lastCurScreenId = hgmCore.GetFrameRateMgr()->GetLastCurScreenId();
58 bool shouldSetRefreshRate = (refreshRate != hgmCore.GetScreenCurrentRefreshRate(id) ||
59 lastCurScreenId != curScreenId);
60 bool needRetrySetRate = false;
61 auto retryIter = setRateRetryMap_.find(id);
62 if (retryIter != setRateRetryMap_.end()) {
63 needRetrySetRate = retryIter->second.first;
64 }
65 if (shouldSetRefreshRate || needRetrySetRate) {
66 RS_LOGD("CommitAndReleaseLayers screenId %{public}d refreshRate %{public}d \
67 needRetrySetRate %{public}d", static_cast<int>(id), refreshRate, needRetrySetRate);
68 int32_t sceneId = (lastCurScreenId != curScreenId || needRetrySetRate) ? SWITCH_SCREEN_SCENE : 0;
69 hgmCore.GetFrameRateMgr()->SetLastCurScreenId(curScreenId);
70 int32_t status = hgmCore.SetScreenRefreshRate(id, sceneId, refreshRate, shouldSetRefreshRate);
71 if (retryIter != setRateRetryMap_.end()) {
72 retryIter->second.first = false;
73 retryIter->second.second = shouldSetRefreshRate ? 0 : retryIter->second.second;
74 }
75 if (status < EXEC_SUCCESS) {
76 RS_LOGD("HgmContext: failed to set refreshRate %{public}d, screenId %{public}" PRIu64 "",
77 refreshRate, id);
78 }
79 }
80 }
81
UpdateRetrySetRateStatus(ScreenId id,int32_t modeId,uint32_t setRateRet)82 void HgmHardwareUtils::UpdateRetrySetRateStatus(ScreenId id, int32_t modeId, uint32_t setRateRet)
83 {
84 if (auto retryIter = setRateRetryMap_.find(id); retryIter != setRateRetryMap_.end()) {
85 auto& [needRetrySetRate, setRateRetryCount] = retryIter->second;
86 needRetrySetRate = (setRateRet == static_cast<uint32_t>(StatusCode::SET_RATE_ERROR));
87 if (!needRetrySetRate) {
88 setRateRetryCount = 0;
89 } else if (setRateRetryCount < MAX_SETRATE_RETRY_COUNT) {
90 setRateRetryCount++;
91 } else {
92 RS_LOGW("skip retrying for ScreenId:%{public}" PRIu64 ", set refresh rate failed more than %{public}d",
93 id, MAX_SETRATE_RETRY_COUNT);
94 needRetrySetRate = false;
95 }
96 RS_LOGD_IF(needRetrySetRate,
97 "RSHardwareThread: need retry set modeId %{public}" PRId32 ", ScreenId:%{public}" PRIu64, modeId, id);
98 }
99 }
100
PerformSetActiveMode(std::shared_ptr<HdiOutput> output,uint64_t timestamp,uint64_t constraintRelativeTime)101 void HgmHardwareUtils::PerformSetActiveMode(
102 std::shared_ptr<HdiOutput> output, uint64_t timestamp, uint64_t constraintRelativeTime)
103 {
104 auto& hgmCore = OHOS::Rosen::HgmCore::Instance();
105 auto screenManager = CreateOrGetScreenManager();
106 if (screenManager == nullptr) {
107 return;
108 }
109 vblankIdleCorrector_.ProcessScreenConstraint(timestamp, constraintRelativeTime);
110 HgmRefreshRates newRate = RSSystemProperties::GetHgmRefreshRatesEnabled();
111 if (hgmRefreshRates_ != newRate) {
112 hgmRefreshRates_ = newRate;
113 hgmCore.SetScreenRefreshRate(screenManager->GetDefaultScreenId(), 0, static_cast<int32_t>(hgmRefreshRates_));
114 }
115
116 std::unique_ptr<std::unordered_map<ScreenId, int32_t>> modeMap(hgmCore.GetModesToApply());
117 if (modeMap == nullptr) {
118 return;
119 }
120
121 RS_TRACE_NAME_FMT("HgmContext::PerformSetActiveMode setting active mode. rate: %d",
122 HgmCore::Instance().GetScreenCurrentRefreshRate(HgmCore::Instance().GetActiveScreenId()));
123 for (auto mapIter = modeMap->begin(); mapIter != modeMap->end(); ++mapIter) {
124 ScreenId id = mapIter->first;
125 int32_t modeId = mapIter->second;
126
127 auto supportedModes = screenManager->GetScreenSupportedModes(id);
128 for (auto mode : supportedModes) {
129 RS_OPTIONAL_TRACE_NAME_FMT(
130 "HgmContext check modes w:%" PRId32", h:%" PRId32", rate:%" PRId32", id:%" PRId32"",
131 mode.GetScreenWidth(), mode.GetScreenHeight(), mode.GetScreenRefreshRate(), mode.GetScreenModeId());
132 }
133
134 uint32_t ret = screenManager->SetScreenActiveMode(id, modeId);
135 if (id <= MAX_HAL_DISPLAY_ID) {
136 setRateRetryMap_.try_emplace(id, std::make_pair(false, 0));
137 UpdateRetrySetRateStatus(id, modeId, ret);
138 } else {
139 RS_LOGD("UpdateRetrySetRateStatus fail, invalid ScreenId:%{public}" PRIu64, id);
140 }
141
142 auto pendingPeriod = hgmCore.GetIdealPeriod(hgmCore.GetScreenCurrentRefreshRate(id));
143 int64_t pendingTimestamp = static_cast<int64_t>(timestamp);
144 if (auto hdiBackend = HdiBackend::GetInstance(); hdiBackend != nullptr) {
145 hdiBackend->SetPendingMode(output, pendingPeriod, pendingTimestamp);
146 hdiBackend->StartSample(output);
147 }
148 }
149 }
150
UpdateRefreshRateParam()151 void HgmHardwareUtils::UpdateRefreshRateParam()
152 {
153 // need to sync the hgm data from main thread.
154 // Temporary sync the timestamp to fix the duplicate time stamp issue.
155 auto& hgmCore = OHOS::Rosen::HgmCore::Instance();
156 bool directComposition = hgmCore.GetDirectCompositionFlag();
157 RS_LOGI_IF(DEBUG_COMPOSER, "GetRefreshRateData period is %{public}d", directComposition);
158 if (directComposition) {
159 hgmCore.SetDirectCompositionFlag(false);
160 }
161 if (directComposition) {
162 refreshRateParam_ = {
163 .rate = hgmCore.GetPendingScreenRefreshRate(),
164 .frameTimestamp = hgmCore.GetCurrentTimestamp(),
165 .actualTimestamp = hgmCore.GetActualTimestamp(),
166 .vsyncId = hgmCore.GetVsyncId(),
167 .constraintRelativeTime = hgmCore.GetPendingConstraintRelativeTime(),
168 .isForceRefresh = hgmCore.GetForceRefreshFlag(),
169 .fastComposeTimeStampDiff = hgmCore.GetFastComposeTimeStampDiff()
170 };
171 } else {
172 refreshRateParam_ = {
173 .rate = RSUniRenderThread::Instance().GetPendingScreenRefreshRate(),
174 .frameTimestamp = RSUniRenderThread::Instance().GetCurrentTimestamp(),
175 .actualTimestamp = RSUniRenderThread::Instance().GetActualTimestamp(),
176 .vsyncId = RSUniRenderThread::Instance().GetVsyncId(),
177 .constraintRelativeTime = RSUniRenderThread::Instance().GetPendingConstraintRelativeTime(),
178 .isForceRefresh = RSUniRenderThread::Instance().GetForceRefreshFlag(),
179 .fastComposeTimeStampDiff = RSUniRenderThread::Instance().GetFastComposeTimeStampDiff()
180 };
181 }
182 }
183 } // namespace Rosen
184 } // namespace OHOS