1 /*
2 * Copyright (c) 2024-2024 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 "rs_vsync_rate_reduce_manager.h"
17 #include <parameters.h>
18 #include <ratio>
19 #include <thread>
20 #include <unordered_set>
21 #include "common/rs_obj_abs_geometry.h"
22 #include "common/rs_optional_trace.h"
23 #include "graphic_feature_param_manager.h"
24 #include "pipeline/main_thread/rs_main_thread.h"
25 #include "platform/common/rs_log.h"
26 #include "rs_trace.h"
27
28 namespace OHOS {
29 namespace Rosen {
30
31 namespace {
32 // reduce the app refresh rate by ratio on the frame rate of entire system.
33 // if frame rate is 120, ratio of 1 means 120, 2 means 60, 3 means 40, 4 means 30
34 // vsync rate table, first dimension means the balance level as one frame duration increased
35 // second dimension means the occlusion level
36 constexpr uint32_t VSYNC_RATE_TABLE[][4] = {
37 {1, 1, 2, 2},
38 {1, 2, 2, 3},
39 {2, 2, 3, 3},
40 {2, 2, 3, 4},
41 {2, 3, 4, 4},
42 };
43 constexpr float V_VAL_MIN = 0.0f;
44 constexpr float V_VAL_MAX = 1.0f;
45 constexpr float WORKLOAD_TIMES[] = {1.0f, 1.5f, 2.0f, 2.5f};
46 // WORKLOAD_TIMES + LEVEL_RANGE_UP, LEVEL_RANGE_UP is 0.0f;
47 constexpr float WORKLOAD_TIMES_UP[] = {1.0f, 1.5f, 2.0f, 2.5f};
48 // WORKLOAD_TIMES - LEVEL_RANGE_DOWN, LEVEL_RANGE_DOWN is 0.2f;
49 constexpr float WORKLOAD_TIMES_DOWN[] = {0.8f, 1.3f, 1.8f, 2.3f};
50 constexpr float V_VAL_INTERVALS[] = {V_VAL_MAX, 0.75f, 0.5f, 0.25f, V_VAL_MIN};
51 constexpr int BALANCE_FRAME_COUNT = 3;
52 constexpr int WORKLOAD_TIMES_SIZE = sizeof(WORKLOAD_TIMES) / sizeof(WORKLOAD_TIMES[0]);
53 constexpr int WORKLOAD_LEVEL_COUNT = sizeof(VSYNC_RATE_TABLE) / sizeof(VSYNC_RATE_TABLE[0]);
54
55 // v_val of the v-rate result
56 constexpr float V_VAL_LEVEL_1 = 1.0f;
57 constexpr float V_VAL_LEVEL_2 = 0.8f;
58 constexpr float V_VAL_LEVEL_3 = 0.6f;
59 constexpr float V_VAL_LEVEL_4 = 0.4f;
60 constexpr float V_VAL_LEVEL_5 = 0.2f;
61 constexpr float V_VAL_LEVEL_6 = 0.1f;
62 constexpr float V_VAL_LEVEL_BEHINDWINDOW = -1.0f;
63 // ratio of area, such as biggest Rect and total visible Area
64 constexpr float CONTINUOUS_RATIO_LEVEL_0 = 4.0f / 8.0f;
65 constexpr float CONTINUOUS_RATIO_LEVEL_1 = 3.0f / 8.0f;
66 constexpr float CONTINUOUS_RATIO_LEVEL_2 = 2.0f / 8.0f;
67 constexpr float CONTINUOUS_RATIO_LEVEL_3 = 1.0f / 8.0f;
68 constexpr float CONTINUOUS_RATIO_LEVEL_4 = 1.0f / 10.0f;
69 constexpr float CONTINUOUS_RATIO_LEVEL_5 = 1.0f / 12.0f;
70 constexpr int64_t PERIOD_CHECK_THRESHOLD = 1000 * 1000 * 1000; // 1000,000,000ns = 1.0s
71 constexpr int32_t DEFAULT_RATE = 1;
72 constexpr int32_t SIMI_VISIBLE_RATE = 2;
73 constexpr int32_t SYSTEM_ANIMATED_SCENES_RATE = 2;
74 constexpr int32_t INVISBLE_WINDOW_RATE = 10;
75 constexpr uint32_t MIN_REFRESH_RATE = 30;
76 constexpr int INVISBLE_WINDOW_VSYNC_RATIO = std::numeric_limits<int>::max();
77 constexpr int V_VAL_LEVEL_6_WINDOW_VSYNC_RATIO = std::numeric_limits<int>::max() >> 1;
78 } // Anonymous namespace
79
SetFocusedNodeId(NodeId focusedNodeId)80 void RSVsyncRateReduceManager::SetFocusedNodeId(NodeId focusedNodeId)
81 {
82 if (!vRateReduceEnabled_) {
83 return;
84 }
85 focusedNodeId_ = focusedNodeId;
86 }
87
PushWindowNodeId(NodeId nodeId)88 void RSVsyncRateReduceManager::PushWindowNodeId(NodeId nodeId)
89 {
90 if (!vRateReduceEnabled_) {
91 return;
92 }
93 curAllMainAndLeashWindowNodesIds_.emplace_back(nodeId);
94 }
95
ClearLastVisMapForVsyncRate()96 void RSVsyncRateReduceManager::ClearLastVisMapForVsyncRate()
97 {
98 if (!vRateReduceEnabled_) {
99 return;
100 }
101 lastVisMapForVSyncVisLevel_.clear();
102 }
103
FrameDurationBegin()104 void RSVsyncRateReduceManager::FrameDurationBegin()
105 {
106 if (!vRateConditionQualified_) {
107 return;
108 }
109 curTime_ = Now();
110 }
111
FrameDurationEnd()112 void RSVsyncRateReduceManager::FrameDurationEnd()
113 {
114 if (!vRateConditionQualified_) {
115 return;
116 }
117 if (oneFramePeriod_ > 0) {
118 float val = static_cast<float>(Now() - curTime_) / static_cast<float>(oneFramePeriod_);
119 EnqueueFrameDuration(val);
120 }
121 curTime_ = 0;
122 }
123
SetIsReduceBySystemAnimatedScenes(bool isReduceBySystemAnimatedScenes)124 void RSVsyncRateReduceManager::SetIsReduceBySystemAnimatedScenes(bool isReduceBySystemAnimatedScenes)
125 {
126 if (!vRateReduceEnabled_) {
127 return;
128 }
129 isReduceBySystemAnimatedScenes_ = isReduceBySystemAnimatedScenes;
130 }
131
EnqueueFrameDuration(float duration)132 void RSVsyncRateReduceManager::EnqueueFrameDuration(float duration)
133 {
134 std::lock_guard<std::mutex> lock(mutexFrameDuration_);
135 while (frameDurations_.size() >= BALANCE_FRAME_COUNT) {
136 frameDurations_.pop_front();
137 }
138 frameDurations_.push_back(duration);
139 }
140
CollectSurfaceVsyncInfo(const ScreenInfo & screenInfo,RSSurfaceRenderNode & surfaceNode)141 void RSVsyncRateReduceManager::CollectSurfaceVsyncInfo(const ScreenInfo& screenInfo, RSSurfaceRenderNode& surfaceNode)
142 {
143 if (!vRateConditionQualified_) {
144 return;
145 }
146 if (surfaceNode.IsHardwareEnabledTopSurface()) {
147 return;
148 }
149
150 if (!surfaceNode.IsSCBNode() || surfaceNode.GetDstRect().IsEmpty() || surfaceNode.IsLeashWindow()) {
151 return;
152 }
153 const auto& nodeId = surfaceNode.GetId();
154 if (surfaceVRateMap_.find(nodeId) != surfaceVRateMap_.end()) {
155 return;
156 }
157 const auto& nodeName = surfaceNode.GetName();
158 auto& geoPtr = surfaceNode.GetRenderProperties().GetBoundsGeometry();
159 if (geoPtr == nullptr) {
160 RS_LOGE("CollectSurfaceVsyncInfo geoPtr is null %{public}s", nodeName.c_str());
161 return;
162 }
163 auto& appAbsRect = geoPtr->GetAbsRect();
164 int width = static_cast<int>(std::round(appAbsRect.width_ * screenInfo.GetRogWidthRatio()));
165 int height = static_cast<int>(std::round(appAbsRect.height_ * screenInfo.GetRogHeightRatio()));
166 SurfaceVRateInfo vRateInfo;
167 vRateInfo.name = nodeName;
168 vRateInfo.nodeId = nodeId;
169 vRateInfo.visibleRegion = surfaceNode.GetVisibleRegion();
170 vRateInfo.visibleRegionBehindWindow = surfaceNode.GetVisibleRegionBehindWindow();
171 vRateInfo.appWindowArea = width * height;
172 surfaceVRateMap_.emplace(nodeId, std::move(vRateInfo));
173 }
174
SetUniVsync()175 void RSVsyncRateReduceManager::SetUniVsync()
176 {
177 if (!vRateConditionQualified_) {
178 return;
179 }
180 RS_TRACE_FUNC();
181 UpdateRatesLevel();
182 CalcRates();
183 NotifyVRates();
184 }
185
UpdateRatesLevel()186 int RSVsyncRateReduceManager::UpdateRatesLevel()
187 {
188 float totalDuration = 0;
189 {
190 std::lock_guard<std::mutex> lock(mutexFrameDuration_);
191 if (frameDurations_.size() < BALANCE_FRAME_COUNT) {
192 return curRatesLevel_;
193 }
194 for (int i = 0; i < BALANCE_FRAME_COUNT; i++) {
195 totalDuration = totalDuration + frameDurations_[i];
196 }
197 frameDurations_.pop_front();
198 }
199 // stale rate
200 int plusLevel = 0;
201 // 1: level up
202 auto lastRatesLevel = curRatesLevel_;
203 int newLevel = -1;
204 for (int i = WORKLOAD_TIMES_SIZE - 1; i >= lastRatesLevel; --i) {
205 if (totalDuration > static_cast<float>(BALANCE_FRAME_COUNT) * WORKLOAD_TIMES_UP[i]) {
206 newLevel = i + 1;
207 break;
208 }
209 }
210 if (newLevel > lastRatesLevel) {
211 plusLevel = newLevel;
212 }
213
214 // 2: level down
215 if (newLevel <= 0) {
216 newLevel = lastRatesLevel;
217 for (int i = 0; i <= lastRatesLevel; ++i) {
218 if (totalDuration < static_cast<float>(BALANCE_FRAME_COUNT) * WORKLOAD_TIMES_DOWN[i]) {
219 newLevel = i;
220 break;
221 }
222 }
223 if (newLevel < lastRatesLevel) {
224 plusLevel = -1; // only down one level
225 }
226 }
227 int tempLevel = plusLevel > 0 ? plusLevel : (curRatesLevel_ + plusLevel);
228 tempLevel = tempLevel > 0 ? tempLevel : 0;
229 curRatesLevel_ = (tempLevel >= WORKLOAD_LEVEL_COUNT) ? WORKLOAD_LEVEL_COUNT - 1 : tempLevel;
230 RS_LOGD("curRatesLevel: [%{public}d], tempLevel: [%{public}d]", curRatesLevel_, tempLevel);
231 return curRatesLevel_;
232 }
233
CalcRates()234 void RSVsyncRateReduceManager::CalcRates()
235 {
236 if (isSystemAnimatedScenes_) {
237 for (const auto& [nodeId, vRateInfo]: surfaceVRateMap_) {
238 vSyncRateMap_[nodeId] = SYSTEM_ANIMATED_SCENES_RATE;
239 auto iter = lastVSyncRateMap_.find(nodeId);
240 SetVSyncRatesChanged(iter == lastVSyncRateMap_.end() || iter->second != SYSTEM_ANIMATED_SCENES_RATE);
241 RS_OPTIONAL_TRACE_NAME_FMT("CalcRates name=%s id=%" PRIu64 ",rate=%d,isSysAni=%d", vRateInfo.name.c_str(),
242 nodeId, SYSTEM_ANIMATED_SCENES_RATE, isSystemAnimatedScenes_);
243 RS_LOGD("CalcRates name=%{public}s id=%{public}" PRIu64 ",rate=%{public}d,isSysAni=%{public}d",
244 vRateInfo.name.c_str(), nodeId, SYSTEM_ANIMATED_SCENES_RATE, isSystemAnimatedScenes_);
245 }
246 return;
247 }
248 for (const auto& [nodeId, vRateInfo]: surfaceVRateMap_) {
249 double vVal = 0;
250 int visArea = vRateInfo.visibleRegion.Area();
251 const bool visibleRegionBehindWindowEmpty = vRateInfo.visibleRegionBehindWindow.IsEmpty();
252 if (vRateInfo.visibleRegion.IsEmpty()) {
253 vVal = V_VAL_MIN;
254 } else if (visibleRegionBehindWindowEmpty) {
255 vVal = V_VAL_LEVEL_BEHINDWINDOW;
256 } else if (nodeId == focusedNodeId_ ||
257 visArea >= std::round(vRateInfo.appWindowArea * CONTINUOUS_RATIO_LEVEL_0)) {
258 vVal = V_VAL_LEVEL_1;
259 } else if (visArea <= std::round(vRateInfo.appWindowArea * CONTINUOUS_RATIO_LEVEL_5)) {
260 vVal = V_VAL_LEVEL_6;
261 } else {
262 RectI maxVisRect = CalcMaxVisibleRect(vRateInfo.visibleRegion, vRateInfo.appWindowArea).ToRectI();
263 vVal = CalcVValByAreas(vRateInfo.appWindowArea, maxVisRect.width_ * maxVisRect.height_, visArea);
264 }
265 auto lastIter = lastVSyncRateMap_.find(nodeId);
266 if (vVal >= V_VAL_MAX && (lastIter == lastVSyncRateMap_.end() || lastIter->second <= DEFAULT_RATE)) {
267 continue;
268 }
269 int rate = GetRateByBalanceLevel(vVal);
270 vSyncRateMap_[nodeId] = rate;
271 SetVSyncRatesChanged(lastIter == lastVSyncRateMap_.end() || lastIter->second != rate);
272 RS_OPTIONAL_TRACE_NAME_FMT("CalcRates name=%s id=%" PRIu64 ",vVal=%.2f,rate=%d,isSysAni=%d",
273 vRateInfo.name.c_str(), nodeId, vVal, rate, isSystemAnimatedScenes_);
274 RS_LOGD("CalcRates name=%{public}s nodeid=%{public}" PRIu64
275 ",vVal=%{public}.2f,rate=%{public}d,isSysAni=%{public}d",
276 vRateInfo.name.c_str(), nodeId, vVal, rate, isSystemAnimatedScenes_);
277 }
278 }
279
NotifyVRates()280 void RSVsyncRateReduceManager::NotifyVRates()
281 {
282 if (vSyncRateMap_.empty() || !CheckNeedNotify()) {
283 return;
284 }
285
286 linkersRateMap_.clear();
287 for (const auto& [nodeId, rate]: vSyncRateMap_) {
288 std::vector<uint64_t> linkerIds = appVSyncDistributor_->GetSurfaceNodeLinkerIds(nodeId);
289 if (rate != 0 && RSSystemParameters::GetVRateControlEnabled()) {
290 for (auto linkerId : linkerIds) {
291 linkersRateMap_.emplace(linkerId, rate);
292 RS_OPTIONAL_TRACE_NAME_FMT("NotifyVRates linkerid = %" PRIu64 " nodeId=%" PRIu64
293 " rate=%d isSysAnimate=%d", linkerId, nodeId, rate, isSystemAnimatedScenes_);
294 RS_LOGD("NotifyVRates linkerid = %{public}" PRIu64 " nodeId=%{public}"
295 PRIu64 " rate=%{public}d isSysAnimate=%{public}d", linkerId, nodeId, rate, isSystemAnimatedScenes_);
296 }
297 }
298 auto iter = lastVSyncRateMap_.find(nodeId);
299 if (iter != lastVSyncRateMap_.end() && iter->second == rate) {
300 continue;
301 }
302 if (RSSystemParameters::GetVRateControlEnabled()) {
303 needPostTask_.exchange(true);
304 }
305 appVSyncDistributor_->SetQosVSyncRate(nodeId, rate, isSystemAnimatedScenes_);
306 }
307
308 lastVSyncRateMap_ = vSyncRateMap_;
309 }
GetRateByBalanceLevel(double vVal)310 int RSVsyncRateReduceManager::GetRateByBalanceLevel(double vVal)
311 {
312 if (std::abs(vVal - V_VAL_LEVEL_BEHINDWINDOW) < 10e-6) {
313 int rateBehindWindow = static_cast<int>(ceil(static_cast<double>(rsRefreshRate_) /
314 RS_REFRESH_RATE_BEHIND_WINDOW));
315 RS_LOGD("RSVsyncRateReduceManager::GetRateByBalanceLevel in behind window condition vVal=%{public}.2f, rate=%d",
316 vVal, rateBehindWindow);
317 return rateBehindWindow;
318 }
319 if (vVal <= 0) {
320 return INVISBLE_WINDOW_VSYNC_RATIO;
321 }
322 if (vVal <= V_VAL_LEVEL_6 && curRatesLevel_ != 0) {
323 return V_VAL_LEVEL_6_WINDOW_VSYNC_RATIO;
324 }
325 if (vVal >= V_VAL_INTERVALS[0]) {
326 return DEFAULT_RATE;
327 }
328 if (curRatesLevel_ > WORKLOAD_LEVEL_COUNT - 1) {
329 RS_LOGE("GetRateByBalanceLevel curRatesLevel error");
330 return DEFAULT_RATE;
331 }
332 uint32_t minRate = rsRefreshRate_ / MIN_REFRESH_RATE;
333 auto& rates = VSYNC_RATE_TABLE[curRatesLevel_];
334 size_t intervalsSize = sizeof(V_VAL_INTERVALS) / sizeof(float);
335 for (size_t i = 1; i < intervalsSize; ++i) {
336 if (vVal > V_VAL_INTERVALS[i]) {
337 return static_cast<int>(std::min(minRate, rates[i - 1]));
338 }
339 }
340 return V_VAL_LEVEL_6_WINDOW_VSYNC_RATIO;
341 }
342
GetMaxVerticalRect(const Occlusion::Region & region)343 inline Occlusion::Rect RSVsyncRateReduceManager::GetMaxVerticalRect(const Occlusion::Region ®ion)
344 {
345 Occlusion::Rect maxRect;
346 auto& regionRects = region.GetRegionRects();
347 for (const auto& regionRect : regionRects) {
348 if (regionRect.Area() > maxRect.Area()) {
349 maxRect = regionRect;
350 }
351 }
352 return maxRect;
353 }
354
CalcMaxVisibleRect(const Occlusion::Region & region,int appWindowArea)355 Occlusion::Rect RSVsyncRateReduceManager::CalcMaxVisibleRect(const Occlusion::Region ®ion,
356 int appWindowArea)
357 {
358 int maxRArea = 0;
359 Occlusion::Rect maxRect;
360 Occlusion::Region srcRegion = region;
361 Occlusion::Rect srcBound = region.GetBound();
362 int minArea = std::round(appWindowArea * CONTINUOUS_RATIO_LEVEL_5);
363
364 const std::vector<Occlusion::Rect>& rects = region.GetRegionRects();
365 std::unordered_set<int> xPositionSet = {srcBound.left_, srcBound.right_};
366 std::vector<int> xPositions;
367 for (const auto &rect: rects) {
368 if (rect.Area() > maxRArea) {
369 maxRect = rect;
370 maxRArea = maxRect.Area();
371 }
372 xPositionSet.emplace(rect.left_);
373 xPositionSet.emplace(rect.right_);
374 }
375 if (maxRArea >= std::round(appWindowArea * CONTINUOUS_RATIO_LEVEL_1)) {
376 return maxRect;
377 }
378 xPositions.assign(xPositionSet.begin(), xPositionSet.end());
379 std::sort(xPositions.begin(), xPositions.end());
380 for (size_t i = 0; i < xPositions.size() - 1; ++i) {
381 for (size_t j = i + 1; j < xPositions.size(); ++j) {
382 Occlusion::Rect subBound(xPositions[i], srcBound.top_, xPositions[j], srcBound.bottom_);
383 int baseArea = std::max(maxRArea, minArea);
384 if (subBound.Area() <= baseArea) {
385 continue;
386 }
387 Occlusion::Region subRegion{subBound};
388 Occlusion::Region verticalRegion = subRegion.And(srcRegion);
389 if (verticalRegion.Area() <= baseArea) {
390 continue;
391 }
392 Occlusion::Rect tmpRect = GetMaxVerticalRect(verticalRegion);
393 if (tmpRect.Area() > maxRArea) {
394 maxRect = tmpRect;
395 maxRArea = tmpRect.Area();
396 }
397 }
398 }
399 return maxRect;
400 }
401
CalcVValByAreas(int windowArea,int maxVisRectArea,int visTotalArea)402 float RSVsyncRateReduceManager::CalcVValByAreas(int windowArea, int maxVisRectArea, int visTotalArea)
403 {
404 int level0Area = std::round(windowArea * CONTINUOUS_RATIO_LEVEL_0);
405 int level1Area = std::round(windowArea * CONTINUOUS_RATIO_LEVEL_1);
406 if (visTotalArea >= level0Area || maxVisRectArea >= level1Area) {
407 return V_VAL_LEVEL_1;
408 }
409 int level2Area = std::round(windowArea * CONTINUOUS_RATIO_LEVEL_2);
410 if (visTotalArea >= level1Area || maxVisRectArea >= level2Area) {
411 return V_VAL_LEVEL_2;
412 }
413 int level3Area = std::round(windowArea * CONTINUOUS_RATIO_LEVEL_3);
414 if (visTotalArea >= level2Area || maxVisRectArea >= level3Area) {
415 return V_VAL_LEVEL_3;
416 }
417 int level4Area = std::round(windowArea * CONTINUOUS_RATIO_LEVEL_4);
418 if (visTotalArea >= level3Area || maxVisRectArea >= level4Area) {
419 return V_VAL_LEVEL_4;
420 }
421 int level5Area = std::round(windowArea * CONTINUOUS_RATIO_LEVEL_5);
422 if (visTotalArea >= level4Area || maxVisRectArea >= level5Area) {
423 return V_VAL_LEVEL_5;
424 }
425 return V_VAL_LEVEL_6;
426 }
427
Now()428 uint64_t RSVsyncRateReduceManager::Now()
429 {
430 return std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::steady_clock::now().time_since_epoch())
431 .count();
432 }
433
SetVSyncRateByVisibleLevel(std::map<NodeId,RSVisibleLevel> & visMapForVsyncRate,std::vector<RSBaseRenderNode::SharedPtr> & curAllSurfaces)434 void RSVsyncRateReduceManager::SetVSyncRateByVisibleLevel(std::map<NodeId, RSVisibleLevel>& visMapForVsyncRate,
435 std::vector<RSBaseRenderNode::SharedPtr>& curAllSurfaces)
436 {
437 if (!vRateConditionQualified_) {
438 return;
439 }
440 if (!RSMainThread::Instance()->IsSystemAnimatedScenesListEmpty()) {
441 visMapForVsyncRate.clear();
442 for (auto it = curAllSurfaces.rbegin(); it != curAllSurfaces.rend(); ++it) {
443 auto curSurface = RSBaseRenderNode::ReinterpretCast<RSSurfaceRenderNode>(*it);
444 if (curSurface == nullptr || curSurface->GetDstRect().IsEmpty() || curSurface->IsLeashWindow()) {
445 continue;
446 }
447 visMapForVsyncRate[curSurface->GetId()] = RSVisibleLevel::RS_SYSTEM_ANIMATE_SCENE;
448 }
449 isReduceBySystemAnimatedScenes_ = true;
450 }
451 NotifyVSyncRates(visMapForVsyncRate);
452 }
453
CheckNeedNotify()454 bool RSVsyncRateReduceManager::CheckNeedNotify()
455 {
456 bool surfaceIdsChanged = lastAllMainAndLeashWindowNodesIds_ != curAllMainAndLeashWindowNodesIds_;
457 bool focusChanged = lastFocusedNodeId_ != focusedNodeId_;
458 bool needRefresh = !isSystemAnimatedScenes_ && isReduceBySystemAnimatedScenes_;
459 bool notifyCdt = vSyncRatesChanged_ || surfaceIdsChanged || focusChanged || needRefresh;
460 RS_LOGD("CheckNeedNotify notifyCdt=%{public}d %{public}s%{public}s%{public}s%{public}s%{public}s", notifyCdt,
461 isSystemAnimatedScenes_ ? "sysAnimated|" : "", needRefresh ? "needR|" : "", vSyncRatesChanged_ ? "ratesC|" : "",
462 surfaceIdsChanged ? "surfaceIdsC|" : "", focusChanged ? "focusIdC" : "");
463 RS_TRACE_NAME_FMT("CheckNeedNotify notifyCdt=%d %s%s%s%s%s", notifyCdt,
464 isSystemAnimatedScenes_ ? "sysAnimated|" : "", needRefresh ? "needR|" : "", vSyncRatesChanged_ ? "ratesC|" : "",
465 surfaceIdsChanged ? "surfaceIdsC|" : "", focusChanged ? "focusIdC" : "");
466 if (!notifyCdt) {
467 return false;
468 }
469 if (surfaceIdsChanged) {
470 lastAllMainAndLeashWindowNodesIds_ = curAllMainAndLeashWindowNodesIds_;
471 }
472 if (focusChanged) {
473 lastFocusedNodeId_ = focusedNodeId_;
474 }
475 if (needRefresh) {
476 isReduceBySystemAnimatedScenes_ = false;
477 }
478 if (surfaceIdsChanged || needRefresh) {
479 for (const auto& [nodeId, rate]: lastVSyncRateMap_) {
480 if (vSyncRateMap_.find(nodeId) == vSyncRateMap_.end()) {
481 vSyncRateMap_.emplace(nodeId, DEFAULT_RATE);
482 }
483 }
484 }
485 if (isSystemAnimatedScenes_) {
486 isReduceBySystemAnimatedScenes_ = true;
487 }
488 return true;
489 }
490
NotifyVSyncRates(const std::map<NodeId,RSVisibleLevel> & vSyncVisLevelMap)491 void RSVsyncRateReduceManager::NotifyVSyncRates(const std::map<NodeId, RSVisibleLevel>& vSyncVisLevelMap)
492 {
493 RS_TRACE_NAME_FMT("NotifyVSyncRates vSyncRates.size=[%lu]", vSyncVisLevelMap.size());
494 if (vSyncVisLevelMap.empty()) {
495 return;
496 }
497 auto notifyVsyncFunc = [distributor = appVSyncDistributor_] (NodeId nodeId, RSVisibleLevel level) {
498 bool isSysAnimate = false;
499 int32_t rate = DEFAULT_RATE;
500 if (level == RSVisibleLevel::RS_SEMI_DEFAULT_VISIBLE) {
501 rate = SIMI_VISIBLE_RATE;
502 } else if (level == RSVisibleLevel::RS_SYSTEM_ANIMATE_SCENE) {
503 isSysAnimate = true;
504 rate = SYSTEM_ANIMATED_SCENES_RATE;
505 } else if (level == RSVisibleLevel::RS_INVISIBLE) {
506 rate = INVISBLE_WINDOW_RATE;
507 } else {
508 rate = DEFAULT_RATE;
509 }
510 distributor->SetQosVSyncRate(nodeId, rate, isSysAnimate);
511 RS_OPTIONAL_TRACE_NAME_FMT("NotifyVSyncRates nodeId=%" PRIu64 " rate=%d isSysAnimate=%d", nodeId, rate,
512 isSysAnimate);
513 };
514
515 bool isVisibleChanged = lastVisMapForVSyncVisLevel_.size() != vSyncVisLevelMap.size();
516 if (!isVisibleChanged) {
517 auto iterCur = vSyncVisLevelMap.begin();
518 auto iterLast = lastVisMapForVSyncVisLevel_.begin();
519 for (; iterCur != vSyncVisLevelMap.end(); iterCur++, iterLast++) {
520 if (iterCur->first != iterLast->first || iterCur->second != iterLast->second) {
521 isVisibleChanged = true;
522 notifyVsyncFunc(iterCur->first, iterCur->second);
523 }
524 }
525 if (isVisibleChanged) {
526 lastVisMapForVSyncVisLevel_ = vSyncVisLevelMap;
527 }
528 } else {
529 lastVisMapForVSyncVisLevel_.clear();
530 for (const auto& [nodeId, visLevel] : vSyncVisLevelMap) {
531 notifyVsyncFunc(nodeId, visLevel);
532 lastVisMapForVSyncVisLevel_.emplace(nodeId, visLevel);
533 }
534 }
535 }
536
Init(const sptr<VSyncDistributor> & appVSyncDistributor)537 void RSVsyncRateReduceManager::Init(const sptr<VSyncDistributor>& appVSyncDistributor)
538 {
539 appVSyncDistributor_ = appVSyncDistributor;
540 isDeviceSupprotVRate_ = VRateParam::GetVRateEnable();
541 vRateReduceEnabled_ = isDeviceSupprotVRate_ && RSSystemParameters::GetVSyncControlEnabled();
542 RS_LOGI("Init vRateReduceEnabled_ is %{public}d", vRateReduceEnabled_);
543 }
544
ResetFrameValues(uint32_t rsRefreshRate)545 void RSVsyncRateReduceManager::ResetFrameValues(uint32_t rsRefreshRate)
546 {
547 vRateConditionQualified_ = false;
548 if (!vRateReduceEnabled_) {
549 return;
550 }
551 focusedNodeId_ = 0;
552 surfaceVRateMap_.clear();
553 isSystemAnimatedScenes_ = !RSMainThread::Instance()->IsSystemAnimatedScenesListEmpty();
554 vSyncRatesChanged_ = false;
555 vSyncRateMap_.clear();
556 curAllMainAndLeashWindowNodesIds_.clear();
557 visMapForVSyncVisLevel_.clear();
558 vRateConditionQualified_ = rsRefreshRate > 0 && appVSyncDistributor_ != nullptr;
559 if (!vRateConditionQualified_) {
560 return;
561 }
562 oneFramePeriod_ = PERIOD_CHECK_THRESHOLD / static_cast<int64_t>(rsRefreshRate);
563 rsRefreshRate_ = rsRefreshRate;
564 }
565 } // namespace Rosen
566 } // namespace OHOS
567