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