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 "ipc_callbacks/rs_surface_buffer_callback.h"
17 #include "pipeline/rs_draw_cmd.h"
18 #include "pipeline/rs_surface_buffer_callback_manager.h"
19 #include "platform/common/rs_log.h"
20 #include "platform/common/rs_system_properties.h"
21 #include "rs_trace.h"
22 
23 namespace OHOS {
24 namespace Rosen {
Instance()25 RSSurfaceBufferCallbackManager& RSSurfaceBufferCallbackManager::Instance()
26 {
27     static RSSurfaceBufferCallbackManager surfaceBufferCallbackMgr;
28     return surfaceBufferCallbackMgr;
29 }
30 
SetRunPolicy(std::function<void (std::function<void ()>)> runPolicy)31 void RSSurfaceBufferCallbackManager::SetRunPolicy(
32     std::function<void(std::function<void()>)> runPolicy)
33 {
34     runPolicy_ = runPolicy;
35 }
36 
SetVSyncFuncs(VSyncFuncs vSyncFuncs)37 void RSSurfaceBufferCallbackManager::SetVSyncFuncs(VSyncFuncs vSyncFuncs)
38 {
39     vSyncFuncs_ = vSyncFuncs;
40 }
41 
SetIsUniRender(bool isUniRender)42 void RSSurfaceBufferCallbackManager::SetIsUniRender(bool isUniRender)
43 {
44     isUniRender_ = isUniRender;
45 }
46 
47 #ifdef RS_ENABLE_VK
SetReleaseFenceForVulkan(int releaseFenceFd,NodeId rootNodeId)48 void RSSurfaceBufferCallbackManager::SetReleaseFenceForVulkan(
49     int releaseFenceFd, NodeId rootNodeId)
50 {
51     if (RSSystemProperties::GetGpuApiType() != GpuApiType::VULKAN) {
52         return;
53     }
54     std::lock_guard<std::mutex> lock { surfaceBufferOpItemMutex_ };
55     for (auto& [_, data] : stagingSurfaceBufferIds_) {
56         auto& fences = data.releaseFences;
57         size_t idx = 0;
58         for (auto& fence : fences) {
59             if (data.isRenderedFlags[idx] && data.rootNodeIds[idx] == rootNodeId) {
60                 fence = new (std::nothrow) SyncFence(::dup(releaseFenceFd));
61                 if (!fence) {
62                     RS_LOGE("RSSurfaceBufferCallbackManager::SetReleaseFenceForVulkan"
63                         " Err on creating SyncFence");
64                 }
65             }
66             ++idx;
67         }
68     }
69 }
70 #endif
71 
RegisterSurfaceBufferCallback(pid_t pid,uint64_t uid,sptr<RSISurfaceBufferCallback> callback)72 void RSSurfaceBufferCallbackManager::RegisterSurfaceBufferCallback(pid_t pid, uint64_t uid,
73     sptr<RSISurfaceBufferCallback> callback)
74 {
75     std::unique_lock<std::shared_mutex> lock { registerSurfaceBufferCallbackMutex_ };
76     auto iter = surfaceBufferCallbacks_.find({pid, uid});
77     if (iter == std::end(surfaceBufferCallbacks_)) {
78         surfaceBufferCallbacks_.insert({{pid, uid}, callback});
79     } else {
80         RS_LOGE("RSSurfaceBufferCallbackManager::RegisterSurfaceBufferCallback Pair:"
81             "[Pid: %{public}s, Uid: %{public}s] exists.",
82             std::to_string(pid).c_str(), std::to_string(uid).c_str());
83     }
84 }
85 
UnregisterSurfaceBufferCallback(pid_t pid)86 void RSSurfaceBufferCallbackManager::UnregisterSurfaceBufferCallback(pid_t pid)
87 {
88     std::unique_lock<std::shared_mutex> lock { registerSurfaceBufferCallbackMutex_ };
89     EraseIf(surfaceBufferCallbacks_, [pid](auto& pair) {
90         return pair.first.first == pid;
91     });
92 }
93 
UnregisterSurfaceBufferCallback(pid_t pid,uint64_t uid)94 void RSSurfaceBufferCallbackManager::UnregisterSurfaceBufferCallback(pid_t pid, uint64_t uid)
95 {
96     std::unique_lock<std::shared_mutex> lock { registerSurfaceBufferCallbackMutex_ };
97     auto iter = surfaceBufferCallbacks_.find({pid, uid});
98     if (iter == std::end(surfaceBufferCallbacks_)) {
99         RS_LOGE("RSSurfaceBufferCallbackManager::UnregisterSurfaceBufferCallback Pair:"
100             "[Pid: %{public}s, Uid: %{public}s] not exists.",
101             std::to_string(pid).c_str(), std::to_string(uid).c_str());
102     } else {
103         surfaceBufferCallbacks_.erase(iter);
104     }
105 }
106 
107 #ifdef ROSEN_OHOS
GetOnFinishCb() const108 RSSurfaceBufferCallbackManager::OnFinishCb RSSurfaceBufferCallbackManager::GetOnFinishCb(
109     ) const
110 {
111     auto mutablePtr = const_cast<RSSurfaceBufferCallbackManager*>(this);
112     return [mutablePtr](const Drawing::DrawSurfaceBufferFinishCbData& data) {
113         mutablePtr->OnFinish(data);
114     };
115 }
116 
GetOnAfterAcquireBufferCb() const117 RSSurfaceBufferCallbackManager::OnAfterAcquireBufferCb RSSurfaceBufferCallbackManager::GetOnAfterAcquireBufferCb(
118     ) const
119 {
120     auto mutablePtr = const_cast<RSSurfaceBufferCallbackManager*>(this);
121     return [mutablePtr](const Drawing::DrawSurfaceBufferAfterAcquireCbData& data) {
122         mutablePtr->OnAfterAcquireBuffer(data);
123     };
124 }
125 #endif
126 
GetSurfaceBufferCallback(pid_t pid,uint64_t uid) const127 sptr<RSISurfaceBufferCallback> RSSurfaceBufferCallbackManager::GetSurfaceBufferCallback(
128     pid_t pid, uint64_t uid) const
129 {
130     std::shared_lock<std::shared_mutex> lock { registerSurfaceBufferCallbackMutex_ };
131     auto iter = surfaceBufferCallbacks_.find({pid, uid});
132     if (iter == std::cend(surfaceBufferCallbacks_)) {
133         RS_LOGE("RSSurfaceBufferCallbackManager::GetSurfaceBufferCallback Pair:"
134             "[Pid: %{public}s, Uid %{public}s] not exists.",
135             std::to_string(pid).c_str(), std::to_string(uid).c_str());
136         return nullptr;
137     }
138     return iter->second;
139 }
140 
GetSurfaceBufferCallbackSize() const141 size_t RSSurfaceBufferCallbackManager::GetSurfaceBufferCallbackSize() const
142 {
143     std::shared_lock<std::shared_mutex> lock { registerSurfaceBufferCallbackMutex_ };
144     return surfaceBufferCallbacks_.size();
145 }
146 
147 #ifdef ROSEN_OHOS
EnqueueSurfaceBufferId(const Drawing::DrawSurfaceBufferFinishCbData & data)148 void RSSurfaceBufferCallbackManager::EnqueueSurfaceBufferId(
149     const Drawing::DrawSurfaceBufferFinishCbData& data)
150 {
151     auto iter = stagingSurfaceBufferIds_.find({data.pid, data.uid});
152     if (iter == std::end(stagingSurfaceBufferIds_)) {
153         std::tie(iter, std::ignore) = stagingSurfaceBufferIds_.insert({{data.pid, data.uid}, {}});
154     }
155     auto& [surfaceBufferIds, isRenderedFlags, fences, rootNodeIds] = iter->second;
156     surfaceBufferIds.push_back(data.surfaceBufferId);
157     isRenderedFlags.push_back(static_cast<uint8_t>(data.isRendered));
158     fences.push_back(data.releaseFence);
159     rootNodeIds.push_back(data.rootNodeId);
160 }
161 #endif
162 
RequestNextVSync()163 void RSSurfaceBufferCallbackManager::RequestNextVSync()
164 {
165     if (vSyncFuncs_.isRequestedNextVSync && !std::invoke(vSyncFuncs_.isRequestedNextVSync)) {
166         if (vSyncFuncs_.requestNextVSync) {
167             std::invoke(vSyncFuncs_.requestNextVSync);
168         }
169     }
170 }
171 
172 #ifdef ROSEN_OHOS
OnFinish(const Drawing::DrawSurfaceBufferFinishCbData & data)173 void RSSurfaceBufferCallbackManager::OnFinish(
174     const Drawing::DrawSurfaceBufferFinishCbData& data)
175 {
176     if (auto callback = GetSurfaceBufferCallback(data.pid, data.uid)) {
177         if (data.isNeedTriggerCbDirectly) {
178             callback->OnFinish({
179                 .uid = data.uid,
180                 .surfaceBufferIds = { data.surfaceBufferId },
181                 .isRenderedFlags = { static_cast<uint8_t>(data.isRendered) },
182                 .releaseFences = { data.releaseFence },
183                 .isUniRender = isUniRender_,
184             });
185         } else {
186             {
187                 std::lock_guard<std::mutex> lock { surfaceBufferOpItemMutex_ };
188                 EnqueueSurfaceBufferId(data);
189             }
190             RequestNextVSync();
191         }
192     } else {
193         RS_LOGE("RSSurfaceBufferCallbackManager::OnFinish Pair:"
194             "[Pid: %{public}s, Uid: %{public}s] Callback not exists.",
195             std::to_string(data.pid).c_str(), std::to_string(data.uid).c_str());
196     }
197 }
198 
OnAfterAcquireBuffer(const Drawing::DrawSurfaceBufferAfterAcquireCbData & data)199 void RSSurfaceBufferCallbackManager::OnAfterAcquireBuffer(
200     const Drawing::DrawSurfaceBufferAfterAcquireCbData& data)
201 {
202     if (auto callback = GetSurfaceBufferCallback(data.pid, data.uid)) {
203         callback->OnAfterAcquireBuffer({
204             .uid = data.uid,
205             .isUniRender = isUniRender_,
206         });
207     } else {
208         RS_LOGE("RSSurfaceBufferCallbackManager::OnAfterAcquireBuffer Pair:"
209             "[Pid: %{public}s, Uid: %{public}s] Callback not exists.",
210             std::to_string(data.pid).c_str(), std::to_string(data.uid).c_str());
211     }
212 }
213 #endif
214 
SerializeBufferIdVec(const std::vector<uint32_t> & bufferIdVec)215 std::string RSSurfaceBufferCallbackManager::SerializeBufferIdVec(
216     const std::vector<uint32_t>& bufferIdVec)
217 {
218     std::string ret;
219     for (const auto& id : bufferIdVec) {
220         ret += std::to_string(id) + ",";
221     }
222     if (!ret.empty()) {
223         ret.pop_back();
224     }
225     return ret;
226 }
227 
RunSurfaceBufferCallback()228 void RSSurfaceBufferCallbackManager::RunSurfaceBufferCallback()
229 {
230     if (GetSurfaceBufferCallbackSize() == 0) {
231         return;
232     }
233     runPolicy_([this]() {
234         if (GetSurfaceBufferCallbackSize() == 0) {
235             return;
236         }
237         std::map<std::pair<pid_t, uint64_t>, BufferQueueData> surfaceBufferIds;
238         {
239             std::lock_guard<std::mutex> lock { surfaceBufferOpItemMutex_ };
240             surfaceBufferIds.swap(stagingSurfaceBufferIds_);
241         }
242         bool isNeedRequestNextVSync = false;
243         for (auto& [code, data] : surfaceBufferIds) {
244             auto [pid, uid] = code;
245             auto callback = GetSurfaceBufferCallback(pid, uid);
246             if (callback) {
247                 if (!data.bufferIds.empty()) {
248                     isNeedRequestNextVSync = true;
249                 } else {
250                     continue;
251                 }
252                 RS_TRACE_NAME_FMT("RSSurfaceBufferCallbackManager::RunSurfaceBufferCallback"
253                     "Release Buffer %s", SerializeBufferIdVec(data.bufferIds).c_str());
254                 callback->OnFinish({
255                     .uid = uid,
256                     .surfaceBufferIds = std::move(data.bufferIds),
257                     .isRenderedFlags = std::move(data.isRenderedFlags),
258 #ifdef ROSEN_OHOS
259                     .releaseFences = std::move(data.releaseFences),
260 #endif
261                     .isUniRender = isUniRender_,
262                 });
263             }
264         }
265         if (isNeedRequestNextVSync) {
266             RequestNextVSync();
267         }
268     });
269 }
270 
271 #ifdef RS_ENABLE_VK
RunSurfaceBufferSubCallbackForVulkan(NodeId rootNodeId)272 void RSSurfaceBufferCallbackManager::RunSurfaceBufferSubCallbackForVulkan(NodeId rootNodeId)
273 {
274     if (RSSystemProperties::GetGpuApiType() != GpuApiType::VULKAN) {
275         return;
276     }
277 
278     if (GetSurfaceBufferCallbackSize() == 0) {
279         return;
280     }
281 
282     // Step 1: Extract BufferQueueData by RootNodeId
283     std::map<std::pair<pid_t, uint64_t>, BufferQueueData> surfaceBufferIds;
284     {
285         std::lock_guard<std::mutex> lock { surfaceBufferOpItemMutex_ };
286         for (auto &[code, data] : stagingSurfaceBufferIds_) {
287             auto [pid, uid] = code;
288             auto& dstBufferQueueData = surfaceBufferIds[{pid, uid}];
289             auto bufferQueueDataBegin = std::tuple {
290                 data.bufferIds.begin(), data.isRenderedFlags.begin(),
291                 data.releaseFences.begin(), data.rootNodeIds.begin() };
292             auto bufferQueueDataEnd = std::tuple {
293                 data.bufferIds.end(), data.isRenderedFlags.end(),
294                 data.releaseFences.end(), data.rootNodeIds.end() };
295             static auto runCondition = [rootNodeId](auto iterTuple) {
296                 return rootNodeId == *std::get<ROOTNODEIDS_POS>(iterTuple);
297             };
298             (void) RSSurfaceBufferCallbackMgrUtil::CopyIf(
299                 bufferQueueDataBegin, bufferQueueDataEnd,
300                 std::tuple {
301                     std::back_inserter(dstBufferQueueData.bufferIds),
302                     std::back_inserter(dstBufferQueueData.isRenderedFlags),
303                     std::back_inserter(dstBufferQueueData.releaseFences),
304                     std::back_inserter(dstBufferQueueData.rootNodeIds),
305                 }, runCondition);
306             auto partitionPoint = RSSurfaceBufferCallbackMgrUtil::RemoveIf(
307                 bufferQueueDataBegin, bufferQueueDataEnd, runCondition);
308             auto resizeSize = std::distance(
309                 data.bufferIds.begin(), std::get<0>(partitionPoint));
310             data.bufferIds.resize(resizeSize);
311             data.isRenderedFlags.resize(resizeSize);
312             data.releaseFences.resize(resizeSize);
313             data.rootNodeIds.resize(resizeSize);
314         }
315     }
316 
317     // step 2: Send BufferQueueData to Arkui
318     bool isNeedRequestNextVSync = false;
319     for (auto& [code, data] : surfaceBufferIds) {
320         auto [pid, uid] = code;
321         auto callback = GetSurfaceBufferCallback(pid, uid);
322         if (callback) {
323             if (!data.bufferIds.empty()) {
324                 isNeedRequestNextVSync = true;
325             } else {
326                 continue;
327             }
328             RS_TRACE_NAME_FMT("RSSurfaceBufferCallbackManager::RunSurfaceBufferSubCallbackForVulkan"
329                 "Release Buffer %s", SerializeBufferIdVec(data.bufferIds).c_str());
330             callback->OnFinish({
331                 .uid = uid,
332                 .surfaceBufferIds = std::move(data.bufferIds),
333                 .isRenderedFlags = std::move(data.isRenderedFlags),
334                 .releaseFences = std::move(data.releaseFences),
335                 .isUniRender = isUniRender_,
336             });
337         }
338     }
339     if (isNeedRequestNextVSync) {
340         RequestNextVSync();
341     }
342 }
343 #endif
344 } // namespace Rosen
345 } // namespace OHOS