• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
16 #include "rs_frame_rate_vote.h"
17 
18 #include <algorithm>
19 
20 #include "hgm_core.h"
21 #include "platform/common/rs_log.h"
22 #include "rs_video_frame_rate_vote.h"
23 #include "sandbox_utils.h"
24 
25 namespace OHOS {
26 namespace Rosen {
27 namespace {
28 const std::string VIDEO_RATE_FLAG = "VIDEO_RATE";
29 const std::string VIDEO_VOTE_FLAG = "VOTER_VIDEO";
30 // USE DURATION TO DETERMINE BARRAGE AND UI
31 constexpr uint64_t DANMU_MAX_INTERVAL_TIME = 50;
32 constexpr int32_t VIDEO_VOTE_DELAYS_TIME = 1000 * 1000;
33 }
34 
RSFrameRateVote()35 RSFrameRateVote::RSFrameRateVote()
36 {
37     ffrtQueue_ = std::make_shared<ffrt::queue>("frame_rate_vote_queue");
38     auto policyConfigData = OHOS::Rosen::HgmCore::Instance().GetPolicyConfigData();
39     if (policyConfigData != nullptr) {
40         isSwitchOn_ = policyConfigData->videoFrameRateVoteSwitch_;
41         RS_LOGI("video vote feature isSwitchOn:%{public}s", isSwitchOn_ ? "true" : "false");
42     }
43 }
44 
~RSFrameRateVote()45 RSFrameRateVote::~RSFrameRateVote()
46 {
47     ffrtQueue_ = nullptr;
48 }
49 
SetTransactionFlags(const std::string & transactionFlags)50 void RSFrameRateVote::SetTransactionFlags(const std::string& transactionFlags)
51 {
52     std::lock_guard<std::mutex> lock(mutex_);
53     transactionFlags_ = transactionFlags;
54 }
55 
CheckSurfaceAndUi()56 void RSFrameRateVote::CheckSurfaceAndUi()
57 {
58     if (!hasUiOrSurface) {
59         return;
60     }
61     hasUiOrSurface = false;
62     auto lastUpdateTime = currentUpdateTime_;
63     currentUpdateTime_ = OHOS::Rosen::HgmCore::Instance().GetActualTimestamp() / NS_PER_MS;
64     auto duration = currentUpdateTime_ > lastUpdateTime ? currentUpdateTime_ - lastUpdateTime : 0;
65     if (duration < DANMU_MAX_INTERVAL_TIME) {
66         if (lastVotedRate_ == OLED_NULL_HZ) {
67             return;
68         }
69         uint64_t currentId = lastSurfaceNodeId_.load();
70         {
71             std::lock_guard<ffrt::mutex> autoLock(ffrtMutex_);
72             auto votingAddress = surfaceVideoFrameRateVote_.find(currentId);
73             if (votingAddress != surfaceVideoFrameRateVote_.end() && votingAddress->second) {
74                 votingAddress->second->ReSetLastRate();
75             }
76         }
77         SurfaceVideoVote(currentId, 0);
78     }
79 }
80 
VideoFrameRateVote(uint64_t surfaceNodeId,OHSurfaceSource sourceType,sptr<SurfaceBuffer> & buffer)81 void RSFrameRateVote::VideoFrameRateVote(uint64_t surfaceNodeId, OHSurfaceSource sourceType,
82     sptr<SurfaceBuffer>& buffer)
83 {
84     // transactionFlags_ format is [pid, eventId]
85     std::string transactionFlags = "";
86     std::string strLastVotedPid;
87     {
88         std::lock_guard<std::mutex> lock(mutex_);
89         transactionFlags = transactionFlags_;
90         strLastVotedPid = "[" + std::to_string(lastVotedPid_) + ",";
91     }
92     if (sourceType != OHSurfaceSource::OH_SURFACE_SOURCE_VIDEO ||
93             transactionFlags.find(strLastVotedPid) != std::string::npos) {
94             hasUiOrSurface = true;
95     }
96     // OH SURFACE SOURCE VIDEO AN UI VOTE
97     if (!isSwitchOn_ || sourceType != OHSurfaceSource::OH_SURFACE_SOURCE_VIDEO || buffer == nullptr) {
98         return;
99     }
100     double videoRate = 0.0;
101     sptr<BufferExtraData> extraData = buffer->GetExtraData();
102     if (extraData != nullptr) {
103         extraData->ExtraGet(VIDEO_RATE_FLAG, videoRate);
104     }
105     auto initTask = [this, surfaceNodeId, videoRate]() {
106         std::lock_guard<ffrt::mutex> autoLock(ffrtMutex_);
107         std::shared_ptr<RSVideoFrameRateVote> rsVideoFrameRateVote;
108         if (surfaceVideoFrameRateVote_.find(surfaceNodeId) == surfaceVideoFrameRateVote_.end()) {
109             rsVideoFrameRateVote = std::make_shared<RSVideoFrameRateVote>(surfaceNodeId,
110                 [this](uint64_t id) { this->ReleaseSurfaceMap(id); },
111                 [this](uint64_t id, uint32_t rate) { this->SurfaceVideoVote(id, rate); });
112             surfaceVideoFrameRateVote_.insert(std::pair<uint64_t, std::shared_ptr<RSVideoFrameRateVote>>(
113                 surfaceNodeId, rsVideoFrameRateVote));
114         } else {
115             rsVideoFrameRateVote = surfaceVideoFrameRateVote_[surfaceNodeId];
116         }
117         rsVideoFrameRateVote->StartVideoFrameRateVote(videoRate);
118     };
119     if (ffrtQueue_) {
120         ffrtQueue_->submit(initTask);
121     }
122 }
123 
ReleaseSurfaceMap(uint64_t surfaceNodeId)124 void RSFrameRateVote::ReleaseSurfaceMap(uint64_t surfaceNodeId)
125 {
126     auto initTask = [this, surfaceNodeId]() {
127         SurfaceVideoVote(surfaceNodeId, 0);
128         std::lock_guard<ffrt::mutex> autoLock(ffrtMutex_);
129         auto it = surfaceVideoFrameRateVote_.find(surfaceNodeId);
130         if (it != surfaceVideoFrameRateVote_.end()) {
131             RS_LOGI("video vote release surfaceNodeId(%{public}s), size(%{public}d)",
132                 std::to_string(surfaceNodeId).c_str(), static_cast<int>(surfaceVideoFrameRateVote_.size()));
133             surfaceVideoFrameRateVote_.erase(it);
134         }
135     };
136     if (ffrtQueue_) {
137         ffrtQueue_->submit(initTask);
138     }
139 }
140 
SurfaceVideoVote(uint64_t surfaceNodeId,uint32_t rate)141 void RSFrameRateVote::SurfaceVideoVote(uint64_t surfaceNodeId, uint32_t rate)
142 {
143     std::lock_guard<std::mutex> lock(mutex_);
144     if (rate == 0) {
145         auto it = surfaceVideoRate_.find(surfaceNodeId);
146         if (it != surfaceVideoRate_.end()) {
147             surfaceVideoRate_.erase(it);
148         }
149     } else {
150         surfaceVideoRate_[surfaceNodeId] = rate;
151     }
152     if (surfaceVideoRate_.size() == 0) {
153         CancelVoteRate(lastVotedPid_, VIDEO_VOTE_FLAG);
154         lastVotedPid_ = DEFAULT_PID;
155         lastVotedRate_ = OLED_NULL_HZ;
156         if (ffrtQueue_ && taskHandler_) {
157             ffrtQueue_->cancel(taskHandler_);
158             taskHandler_ = nullptr;
159         }
160         return;
161     }
162     auto maxElement = std::max_element(surfaceVideoRate_.begin(), surfaceVideoRate_.end(),
163         [](const auto& lhs, const auto& rhs) { return lhs.second < rhs.second; });
164     uint32_t maxRate = maxElement->second;
165     pid_t maxPid = ExtractPid(maxElement->first);
166     lastSurfaceNodeId_ = maxElement->first;
167     if (maxRate == lastVotedRate_ && maxPid == lastVotedPid_) {
168         return;
169     }
170     CancelVoteRate(lastVotedPid_, VIDEO_VOTE_FLAG);
171     lastVotedPid_ = maxPid;
172     lastVotedRate_ = maxRate;
173     // Delay for one second to stabilize the voting
174     if (ffrtQueue_ && taskHandler_) {
175         ffrtQueue_->cancel(taskHandler_);
176         taskHandler_ = nullptr;
177     }
178     auto initTask = [this, maxPid, maxRate]() {
179         VoteRate(maxPid, VIDEO_VOTE_FLAG, maxRate);
180     };
181     ffrt::task_attr taskAttr;
182     taskAttr.delay(VIDEO_VOTE_DELAYS_TIME);
183     if (ffrtQueue_) {
184         taskHandler_ = ffrtQueue_->submit_h(initTask, taskAttr);
185     }
186 }
187 
VoteRate(pid_t pid,std::string eventName,uint32_t rate)188 void RSFrameRateVote::VoteRate(pid_t pid, std::string eventName, uint32_t rate)
189 {
190     isVoted_ = true;
191     EventInfo eventInfo = {
192         .eventName = eventName,
193         .eventStatus = true,
194         .minRefreshRate = rate,
195         .maxRefreshRate = rate,
196     };
197     NotifyRefreshRateEvent(pid, eventInfo);
198 }
199 
CancelVoteRate(pid_t pid,std::string eventName)200 void RSFrameRateVote::CancelVoteRate(pid_t pid, std::string eventName)
201 {
202     if (!isVoted_) {
203         return;
204     }
205     isVoted_ = false;
206     EventInfo eventInfo = {
207         .eventName = eventName,
208         .eventStatus = false,
209     };
210     NotifyRefreshRateEvent(pid, eventInfo);
211 }
212 
NotifyRefreshRateEvent(pid_t pid,EventInfo eventInfo)213 void RSFrameRateVote::NotifyRefreshRateEvent(pid_t pid, EventInfo eventInfo)
214 {
215     if (pid > DEFAULT_PID) {
216         RS_LOGI("video vote pid:%{public}d rate(%{public}u, %{public}u)",
217             pid, eventInfo.minRefreshRate, eventInfo.maxRefreshRate);
218         HgmTaskHandleThread::Instance().PostTask([pid, eventInfo]() {
219             auto frameRateMgr = HgmCore::Instance().GetFrameRateMgr();
220             if (frameRateMgr != nullptr) {
221                 frameRateMgr->HandleRefreshRateEvent(pid, eventInfo);
222             }
223         });
224     }
225 }
226 } // namespace Rosen
227 } // namespace OHOS