1 /*
2 * Copyright (c) 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 #include <algorithm>
16 #include "rs_frame_rate_vote.h"
17 #include "hgm_core.h"
18 #include "platform/common/rs_log.h"
19 #include "sandbox_utils.h"
20
21 namespace OHOS {
22 namespace Rosen {
23 namespace {
24 const std::string VIDEO_RATE_FLAG = "VIDEO_RATE";
25 const std::string VIDEO_VOTE_FLAG = "VOTER_VIDEO";
26 }
27
RSFrameRateVote()28 RSFrameRateVote::RSFrameRateVote()
29 {
30 frameRateMgr_ = OHOS::Rosen::HgmCore::Instance().GetFrameRateMgr();
31 ffrtQueue_ = std::make_shared<ffrt::queue>("frame_rate_vote_queue");
32 auto policyConfigData = OHOS::Rosen::HgmCore::Instance().GetPolicyConfigData();
33 if (policyConfigData != nullptr) {
34 isSwitchOn_ = policyConfigData->videoFrameRateVoteSwitch_;
35 RS_LOGI("video vote feature isSwitchOn:%{public}s", isSwitchOn_ ? "true" : "false");
36 }
37 }
38
~RSFrameRateVote()39 RSFrameRateVote::~RSFrameRateVote()
40 {
41 frameRateMgr_ = nullptr;
42 ffrtQueue_ = nullptr;
43 }
44
VideoFrameRateVote(uint64_t surfaceNodeId,OHSurfaceSource sourceType,sptr<SurfaceBuffer> & buffer)45 void RSFrameRateVote::VideoFrameRateVote(uint64_t surfaceNodeId, OHSurfaceSource sourceType,
46 sptr<SurfaceBuffer>& buffer)
47 {
48 if (!isSwitchOn_ || sourceType != OHSurfaceSource::OH_SURFACE_SOURCE_VIDEO || buffer == nullptr) {
49 return;
50 }
51 double videoRate = 0.0;
52 sptr<BufferExtraData> extraData = buffer->GetExtraData();
53 if (extraData != nullptr) {
54 extraData->ExtraGet(VIDEO_RATE_FLAG, videoRate);
55 }
56 std::lock_guard<ffrt::mutex> autoLock(ffrtMutex_);
57 auto initTask = [this, surfaceNodeId, videoRate]() {
58 std::shared_ptr<RSVideoFrameRateVote> rsVideoFrameRateVote;
59 if (surfaceVideoFrameRateVote_.find(surfaceNodeId) == surfaceVideoFrameRateVote_.end()) {
60 rsVideoFrameRateVote = std::make_shared<RSVideoFrameRateVote>(surfaceNodeId,
61 [this](uint64_t id) { this->ReleaseSurfaceMap(id); },
62 [this](uint64_t id, uint32_t rate) { this->SurfaceVideoVote(id, rate); });
63 surfaceVideoFrameRateVote_.insert(std::pair<uint64_t, std::shared_ptr<RSVideoFrameRateVote>>(
64 surfaceNodeId, rsVideoFrameRateVote));
65 } else {
66 rsVideoFrameRateVote = surfaceVideoFrameRateVote_[surfaceNodeId];
67 }
68 rsVideoFrameRateVote->StartVideoFrameRateVote(videoRate);
69 };
70 if (ffrtQueue_) {
71 ffrtQueue_->submit(initTask);
72 }
73 }
74
ReleaseSurfaceMap(uint64_t surfaceNodeId)75 void RSFrameRateVote::ReleaseSurfaceMap(uint64_t surfaceNodeId)
76 {
77 std::lock_guard<ffrt::mutex> autoLock(ffrtMutex_);
78 auto initTask = [this, surfaceNodeId]() {
79 SurfaceVideoVote(surfaceNodeId, 0);
80 auto it = surfaceVideoFrameRateVote_.find(surfaceNodeId);
81 if (it != surfaceVideoFrameRateVote_.end()) {
82 RS_LOGI("video vote release surfaceNodeId(%{public}s), size(%{public}d)",
83 std::to_string(surfaceNodeId).c_str(), static_cast<int>(surfaceVideoFrameRateVote_.size()));
84 surfaceVideoFrameRateVote_.erase(it);
85 }
86 };
87 if (ffrtQueue_) {
88 ffrtQueue_->submit(initTask);
89 }
90 }
91
SurfaceVideoVote(uint64_t surfaceNodeId,uint32_t rate)92 void RSFrameRateVote::SurfaceVideoVote(uint64_t surfaceNodeId, uint32_t rate)
93 {
94 std::lock_guard<std::mutex> lock(mutex_);
95 if (rate == 0) {
96 auto it = surfaceVideoRate_.find(surfaceNodeId);
97 if (it != surfaceVideoRate_.end()) {
98 surfaceVideoRate_.erase(it);
99 }
100 } else {
101 surfaceVideoRate_[surfaceNodeId] = rate;
102 }
103 if (surfaceVideoRate_.size() == 0) {
104 CancelVoteRate(lastVotedPid_, VIDEO_VOTE_FLAG);
105 lastVotedPid_ = DEFAULT_PID;
106 lastVotedRate_ = OLED_NULL_HZ;
107 return;
108 }
109 auto maxElement = std::max_element(surfaceVideoRate_.begin(), surfaceVideoRate_.end(),
110 [] (const auto& lhs, const auto& rhs) { return lhs.second < rhs.second; });
111 uint32_t maxRate = maxElement->second;
112 pid_t maxPid = ExtractPid(maxElement->first);
113 if (maxRate == lastVotedRate_ && maxPid == lastVotedPid_) {
114 return;
115 }
116 CancelVoteRate(lastVotedPid_, VIDEO_VOTE_FLAG);
117 VoteRate(maxPid, VIDEO_VOTE_FLAG, maxRate);
118 lastVotedPid_ = maxPid;
119 lastVotedRate_ = maxRate;
120 }
121
VoteRate(pid_t pid,std::string eventName,uint32_t rate)122 void RSFrameRateVote::VoteRate(pid_t pid, std::string eventName, uint32_t rate)
123 {
124 isVoted_ = true;
125 EventInfo eventInfo = {
126 .eventName = eventName,
127 .eventStatus = true,
128 .minRefreshRate = rate,
129 .maxRefreshRate = rate,
130 };
131 NotifyRefreshRateEvent(pid, eventInfo);
132 }
133
CancelVoteRate(pid_t pid,std::string eventName)134 void RSFrameRateVote::CancelVoteRate(pid_t pid, std::string eventName)
135 {
136 if (!isVoted_) {
137 return;
138 }
139 isVoted_ = false;
140 EventInfo eventInfo = {
141 .eventName = eventName,
142 .eventStatus = false,
143 };
144 NotifyRefreshRateEvent(pid, eventInfo);
145 }
146
NotifyRefreshRateEvent(pid_t pid,EventInfo eventInfo)147 void RSFrameRateVote::NotifyRefreshRateEvent(pid_t pid, EventInfo eventInfo)
148 {
149 if (frameRateMgr_ && pid > DEFAULT_PID) {
150 RS_LOGI("video vote pid:%{public}d rate(%{public}u, %{public}u)",
151 pid, eventInfo.minRefreshRate, eventInfo.maxRefreshRate);
152 frameRateMgr_->HandleRefreshRateEvent(pid, eventInfo);
153 }
154 }
155 } // namespace Rosen
156 } // namespace OHOS