1 /*
2  * Copyright (c) 2023 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 "pipeline/rs_divided_ui_capture.h"
17 
18 #include <memory>
19 #include <mutex>
20 #ifdef ROSEN_OHOS
21 #include <sys/mman.h>
22 #endif
23 
24 #include "utils/matrix.h"
25 
26 #include "common/rs_common_def.h"
27 #include "common/rs_obj_abs_geometry.h"
28 #include "offscreen_render/rs_offscreen_render_thread.h"
29 #include "pipeline/rs_canvas_drawing_render_node.h"
30 #include "pipeline/rs_dirty_region_manager.h"
31 #include "pipeline/rs_render_node_map.h"
32 #include "pipeline/rs_render_thread.h"
33 #include "pipeline/rs_root_render_node.h"
34 #include "render/rs_pixel_map_util.h"
35 #include "transaction/rs_render_service_client.h"
36 #include "platform/common/rs_log.h"
37 #include "platform/common/rs_system_properties.h"
38 
39 namespace OHOS {
40 namespace Rosen {
41 
42 const int FAKE_WIDTH = 10; // When the width and height of the node are not set, use the fake width
43 const int FAKE_HEIGHT = 10; // When the width and height of the node are not set, use the fake height
44 const int MAX_WAIT_TIME = 2000;
45 
TakeLocalCapture()46 std::shared_ptr<Media::PixelMap> RSDividedUICapture::TakeLocalCapture()
47 {
48     if (ROSEN_EQ(scaleX_, 0.f) || ROSEN_EQ(scaleY_, 0.f) || scaleX_ < 0.f || scaleY_ < 0.f) {
49         ROSEN_LOGE("RSDividedUICapture::TakeLocalCapture: scale is invalid.");
50         return nullptr;
51     }
52     auto node = RSRenderThread::Instance().GetContext().GetNodeMap().GetRenderNode<RSRenderNode>(nodeId_);
53     if (node == nullptr) {
54         ROSEN_LOGE("RSDividedUICapture::TakeLocalCapture node is nullptr return");
55         return nullptr;
56     }
57     std::shared_ptr<RSDividedUICaptureVisitor> visitor =
58         std::make_shared<RSDividedUICaptureVisitor>(nodeId_, scaleX_, scaleY_);
59     auto recordingCanvas = std::make_shared<ExtendRecordingCanvas>(FAKE_WIDTH, FAKE_HEIGHT);
60     PostTaskToRTRecord(recordingCanvas, node, visitor);
61     auto drawCallList = recordingCanvas->GetDrawCmdList();
62     std::shared_ptr<Media::PixelMap> pixelmap = CreatePixelMapByNode(node);
63     if (pixelmap == nullptr) {
64         ROSEN_LOGE("RSDividedUICapture::TakeLocalCapture: pixelmap == nullptr!");
65         return nullptr;
66     }
67     auto drSurface = CreateSurface(pixelmap);
68     if (drSurface == nullptr) {
69         return nullptr;
70     }
71     auto canvas = std::make_shared<RSPaintFilterCanvas>(drSurface.get());
72     drawCallList->Playback(*canvas);
73     return pixelmap;
74 }
75 
CreatePixelMapByNode(std::shared_ptr<RSRenderNode> node) const76 std::shared_ptr<Media::PixelMap> RSDividedUICapture::CreatePixelMapByNode(std::shared_ptr<RSRenderNode> node) const
77 {
78     int pixmapWidth = node->GetRenderProperties().GetBoundsWidth();
79     int pixmapHeight = node->GetRenderProperties().GetBoundsHeight();
80     Media::InitializationOptions opts;
81     opts.size.width = ceil(pixmapWidth * scaleX_);
82     opts.size.height = ceil(pixmapHeight * scaleY_);
83     return Media::PixelMap::Create(opts);
84 }
85 
CreateSurface(const std::shared_ptr<Media::PixelMap> & pixelmap) const86 std::shared_ptr<Drawing::Surface> RSDividedUICapture::CreateSurface(
87     const std::shared_ptr<Media::PixelMap>& pixelmap) const
88 {
89     if (pixelmap == nullptr) {
90         ROSEN_LOGE("RSDividedUICapture::CreateSurface: pixelmap == nullptr");
91         return nullptr;
92     }
93     auto address = const_cast<uint32_t*>(pixelmap->GetPixel32(0, 0));
94     if (address == nullptr) {
95         ROSEN_LOGE("RSDividedUICapture::CreateSurface: address == nullptr");
96         return nullptr;
97     }
98     Drawing::BitmapFormat format = { Drawing::ColorType::COLORTYPE_RGBA_8888, Drawing::AlphaType::ALPHATYPE_PREMUL };
99     Drawing::Bitmap bitmap;
100     bitmap.Build(pixelmap->GetWidth(), pixelmap->GetHeight(), format);
101     bitmap.SetPixels(address);
102 
103     auto surface = std::make_shared<Drawing::Surface>();
104     surface->Bind(bitmap);
105     return surface;
106 }
107 
SetCanvas(std::shared_ptr<ExtendRecordingCanvas> canvas)108 void RSDividedUICapture::RSDividedUICaptureVisitor::SetCanvas(std::shared_ptr<ExtendRecordingCanvas> canvas)
109 {
110     if (canvas == nullptr) {
111         ROSEN_LOGE("RSDividedUICaptureVisitor::SetCanvas: canvas == nullptr");
112         return;
113     }
114     canvas_ = std::make_shared<RSPaintFilterCanvas>(canvas.get());
115     canvas_->Scale(scaleX_, scaleY_);
116     canvas_->SetRecordingState(true);
117 }
118 
SetPaintFilterCanvas(std::shared_ptr<RSPaintFilterCanvas> canvas)119 void RSDividedUICapture::RSDividedUICaptureVisitor::SetPaintFilterCanvas(std::shared_ptr<RSPaintFilterCanvas> canvas)
120 {
121     if (canvas == nullptr) {
122         ROSEN_LOGE("RSDividedUICaptureVisitor::SetCanvas: canvas == nullptr");
123         return;
124     }
125     canvas_ = canvas;
126     canvas_->Scale(scaleX_, scaleY_);
127 }
128 
PostTaskToRTRecord(std::shared_ptr<ExtendRecordingCanvas> canvas,std::shared_ptr<RSRenderNode> node,std::shared_ptr<RSDividedUICaptureVisitor> visitor)129 void RSDividedUICapture::PostTaskToRTRecord(std::shared_ptr<ExtendRecordingCanvas> canvas,
130     std::shared_ptr<RSRenderNode> node, std::shared_ptr<RSDividedUICaptureVisitor> visitor)
131 {
132     std::function<void()> recordingDrawCall = [canvas, node, visitor]() -> void {
133         visitor->SetCanvas(canvas);
134         if (!node->IsOnTheTree()) {
135             node->ApplyModifiers();
136             node->Prepare(visitor);
137         }
138         node->Process(visitor);
139     };
140     RSRenderThread::Instance().PostSyncTask(recordingDrawCall);
141 }
142 
ProcessChildren(RSRenderNode & node)143 void RSDividedUICapture::RSDividedUICaptureVisitor::ProcessChildren(RSRenderNode& node)
144 {
145     for (auto& child : *node.GetSortedChildren()) {
146         child->Process(shared_from_this());
147     }
148 }
149 
ProcessRootRenderNode(RSRootRenderNode & node)150 void RSDividedUICapture::RSDividedUICaptureVisitor::ProcessRootRenderNode(RSRootRenderNode& node)
151 {
152     if (!node.ShouldPaint()) {
153         ROSEN_LOGD("RSDividedUICaptureVisitor::ProcessRootRenderNode, no need process");
154         return;
155     }
156 
157     if (!canvas_) {
158         ROSEN_LOGE("RSDividedUICaptureVisitor::ProcessRootRenderNode, canvas is nullptr");
159         return;
160     }
161 
162     canvas_->Save();
163     ProcessCanvasRenderNode(node);
164     canvas_->Restore();
165 }
166 
ProcessCanvasRenderNode(RSCanvasRenderNode & node)167 void RSDividedUICapture::RSDividedUICaptureVisitor::ProcessCanvasRenderNode(RSCanvasRenderNode& node)
168 {
169     if (!node.ShouldPaint()) {
170         ROSEN_LOGD("RSDividedUICaptureVisitor::ProcessCanvasRenderNode, no need process");
171         return;
172     }
173     if (!canvas_) {
174         ROSEN_LOGE("RSDividedUICaptureVisitor::ProcessCanvasRenderNode, canvas is nullptr");
175         return;
176     }
177     if (node.GetId() == nodeId_) {
178         // When drawing nodes, canvas will offset the bounds value, so we will move in reverse here first
179         const auto& property = node.GetRenderProperties();
180         auto& geoPtr = (property.GetBoundsGeometry());
181         Drawing::Matrix relativeMatrix;
182         relativeMatrix.Set(Drawing::Matrix::SCALE_X, scaleX_);
183         relativeMatrix.Set(Drawing::Matrix::SCALE_Y, scaleY_);
184         Drawing::Matrix invertMatrix;
185         if (geoPtr && geoPtr->GetMatrix().Invert(invertMatrix)) {
186             relativeMatrix.PreConcat(invertMatrix);
187         }
188         canvas_->SetMatrix(relativeMatrix);
189     }
190     node.ProcessRenderBeforeChildren(*canvas_);
191     if (node.GetType() == RSRenderNodeType::CANVAS_DRAWING_NODE) {
192         auto canvasDrawingNode = node.ReinterpretCastTo<RSCanvasDrawingRenderNode>();
193         if (!canvasDrawingNode->IsOnTheTree()) {
194             canvasDrawingNode->ProcessRenderContents(*canvas_);
195         } else {
196             Drawing::Bitmap bitmap = canvasDrawingNode->GetBitmap();
197             canvas_->DrawBitmap(bitmap, 0, 0);
198         }
199     } else {
200         node.ProcessRenderContents(*canvas_);
201     }
202     ProcessChildren(node);
203     node.ProcessRenderAfterChildren(*canvas_);
204 }
205 
ProcessEffectRenderNode(RSEffectRenderNode & node)206 void RSDividedUICapture::RSDividedUICaptureVisitor::ProcessEffectRenderNode(RSEffectRenderNode& node)
207 {
208     if (!node.ShouldPaint()) {
209         RS_LOGD("RSDividedUICapture::RSDividedUICaptureVisitor, no need process");
210         return;
211     }
212     if (!canvas_) {
213         RS_LOGE("RSDividedUICapture::RSDividedUICaptureVisitor, canvas is nullptr");
214         return;
215     }
216     node.ProcessRenderBeforeChildren(*canvas_);
217     ProcessChildren(node);
218     node.ProcessRenderAfterChildren(*canvas_);
219 }
220 
221 class RSOffscreenRenderCallback : public SurfaceCaptureCallback {
222 public:
OnSurfaceCapture(std::shared_ptr<Media::PixelMap> pixelmap)223     void OnSurfaceCapture(std::shared_ptr<Media::PixelMap> pixelmap) override
224     {
225         std::unique_lock<std::mutex> lock(mutex_);
226         if (!flag_) {
227             pixelMap_ = pixelmap;
228             flag_ = true;
229         }
230         conditionVariable_.notify_one();
231     }
IsReady() const232     bool IsReady() const
233     {
234         return flag_;
235     }
GetResult(long timeOut)236     std::shared_ptr<Media::PixelMap> GetResult(long timeOut)
237     {
238         std::unique_lock<std::mutex> lock(mutex_);
239         if (!conditionVariable_.wait_for(lock, std::chrono::milliseconds(timeOut), [this] { return IsReady(); })) {
240             ROSEN_LOGE("wait for %{public}lu timeout", timeOut);
241         }
242         return pixelMap_;
243     }
244 private:
245     std::shared_ptr<Media::PixelMap> pixelMap_ = nullptr;
246     std::mutex mutex_;
247     std::condition_variable conditionVariable_;
248     bool flag_ = false;
249 };
250 
ProcessSurfaceRenderNode(RSSurfaceRenderNode & node)251 void RSDividedUICapture::RSDividedUICaptureVisitor::ProcessSurfaceRenderNode(RSSurfaceRenderNode& node)
252 {
253     if (!canvas_) {
254         ROSEN_LOGE("RSDividedUICaptureVisitor::ProcessSurfaceRenderNode, canvas is nullptr");
255         return;
256     }
257     if (!node.GetRenderProperties().GetVisible()) {
258         ROSEN_LOGI(
259             "RSDividedUICaptureVisitor::ProcessSurfaceRenderNode node : %{public}" PRIu64 " is invisible",
260             node.GetId());
261         return;
262     }
263     std::shared_ptr<RSOffscreenRenderCallback> callback = std::make_shared<RSOffscreenRenderCallback>();
264     auto renderServiceClient = std::make_unique<RSRenderServiceClient>();
265     RSSurfaceCaptureConfig captureConfig;
266     captureConfig.scaleX = scaleX_;
267     captureConfig.scaleY = scaleY_;
268     captureConfig.captureType = SurfaceCaptureType::UICAPTURE;
269     renderServiceClient->TakeSurfaceCapture(node.GetId(), callback, captureConfig);
270     std::shared_ptr<Media::PixelMap> pixelMap = callback->GetResult(MAX_WAIT_TIME);
271     if (pixelMap == nullptr) {
272         ROSEN_LOGE("RSDividedUICaptureVisitor::TakeLocalCapture failed to get pixelmap, return nullptr!");
273         return;
274     }
275     // draw pixelmap in canvas
276     auto image = RSPixelMapUtil::ExtractDrawingImage(pixelMap);
277     canvas_->DrawImage(*image, node.GetRenderProperties().GetBoundsPositionX(),
278         node.GetRenderProperties().GetBoundsPositionY(), Drawing::SamplingOptions());
279     ProcessChildren(node);
280 }
281 
PrepareChildren(RSRenderNode & node)282 void RSDividedUICapture::RSDividedUICaptureVisitor::PrepareChildren(RSRenderNode& node)
283 {
284     for (auto& child : *node.GetSortedChildren()) {
285         child->Prepare(shared_from_this());
286     }
287 }
288 
PrepareCanvasRenderNode(RSCanvasRenderNode & node)289 void RSDividedUICapture::RSDividedUICaptureVisitor::PrepareCanvasRenderNode(RSCanvasRenderNode& node)
290 {
291     auto dirtyManager = std::make_shared<RSDirtyRegionManager>();
292     node.Update(*dirtyManager, nullptr, false);
293     PrepareChildren(node);
294 }
295 
PrepareSurfaceRenderNode(RSSurfaceRenderNode & node)296 void RSDividedUICapture::RSDividedUICaptureVisitor::PrepareSurfaceRenderNode(RSSurfaceRenderNode& node)
297 {
298     auto dirtyManager = std::make_shared<RSDirtyRegionManager>();
299     node.Update(*dirtyManager, nullptr, false);
300     PrepareChildren(node);
301 }
302 
PrepareRootRenderNode(RSRootRenderNode & node)303 void RSDividedUICapture::RSDividedUICaptureVisitor::PrepareRootRenderNode(RSRootRenderNode& node)
304 {
305     PrepareCanvasRenderNode(node);
306 }
307 
PrepareEffectRenderNode(RSEffectRenderNode & node)308 void RSDividedUICapture::RSDividedUICaptureVisitor::PrepareEffectRenderNode(RSEffectRenderNode& node)
309 {
310     auto dirtyManager = std::make_shared<RSDirtyRegionManager>();
311     node.Update(*dirtyManager, nullptr, false);
312     PrepareChildren(node);
313 }
314 } // namespace Rosen
315 } // namespace OHOS
316