1 /*
2 * Copyright (c) 2021-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 "feature/capture/rs_surface_capture_task.h"
17
18 #include <memory>
19 #include <sys/mman.h>
20
21 #include "rs_trace.h"
22
23 #include "common/rs_background_thread.h"
24 #include "common/rs_obj_abs_geometry.h"
25 #include "draw/color.h"
26 #include "draw/surface.h"
27 #include "drawable/rs_display_render_node_drawable.h"
28 #include "memory/rs_tag_tracker.h"
29 #include "pipeline/render_thread/rs_base_render_engine.h"
30 #include "pipeline/render_thread/rs_composer_adapter.h"
31 #include "pipeline/render_thread/rs_uni_render_util.h"
32 #include "pipeline/rs_base_render_node.h"
33 #include "pipeline/rs_canvas_drawing_render_node.h"
34 #include "pipeline/rs_display_render_node.h"
35 #include "pipeline/render_thread/rs_divided_render_util.h"
36 #include "pipeline/rs_effect_render_node.h"
37 #include "pipeline/main_thread/rs_main_thread.h"
38 #include "pipeline/main_thread/rs_render_service_connection.h"
39 #include "pipeline/rs_root_render_node.h"
40 #include "pipeline/rs_surface_render_node.h"
41 #include "pipeline/rs_uni_render_judgement.h"
42 #include "platform/common/rs_log.h"
43 #include "platform/drawing/rs_surface.h"
44 #include "render/rs_drawing_filter.h"
45 #include "render/rs_skia_filter.h"
46 #include "screen_manager/rs_screen_manager.h"
47 #include "screen_manager/rs_screen_mode_info.h"
48 namespace OHOS {
49 namespace Rosen {
Run(sptr<RSISurfaceCaptureCallback> callback)50 bool RSSurfaceCaptureTask::Run(sptr<RSISurfaceCaptureCallback> callback)
51 {
52 if (ROSEN_EQ(captureConfig_.scaleX, 0.f) || ROSEN_EQ(captureConfig_.scaleY, 0.f) ||
53 captureConfig_.scaleX < 0.f || captureConfig_.scaleY < 0.f) {
54 RS_LOGE("RSSurfaceCaptureTask::Run: SurfaceCapture scale is invalid.");
55 return false;
56 }
57 auto node = RSMainThread::Instance()->GetContext().GetNodeMap().GetRenderNode(nodeId_);
58 if (node == nullptr) {
59 RS_LOGE("RSSurfaceCaptureTask::Run: node is nullptr");
60 return false;
61 }
62 std::unique_ptr<Media::PixelMap> pixelmap;
63 visitor_ = std::make_shared<RSSurfaceCaptureVisitor>(captureConfig_, RSUniRenderJudgement::IsUniRender());
64 std::string nodeName("RSSurfaceCaptureTask");
65 std::shared_ptr<Drawing::ColorSpace> colorSpace = nullptr;
66 if (auto surfaceNode = node->ReinterpretCastTo<RSSurfaceRenderNode>()) {
67 pixelmap = CreatePixelMapBySurfaceNode(surfaceNode, visitor_->IsUniRender());
68 visitor_->IsDisplayNode(false);
69 nodeName = surfaceNode->GetName();
70 } else if (auto displayNode = node->ReinterpretCastTo<RSDisplayRenderNode>()) {
71 GraphicColorGamut colorGamut = displayNode->GetColorSpace();
72 if (colorGamut != GraphicColorGamut::GRAPHIC_COLOR_GAMUT_SRGB) {
73 colorSpace = RSBaseRenderEngine::ConvertColorGamutToDrawingColorSpace(colorGamut);
74 }
75 pixelmap = CreatePixelMapByDisplayNode(displayNode, visitor_->IsUniRender());
76 visitor_->IsDisplayNode(true);
77 } else {
78 RS_LOGE("RSSurfaceCaptureTask::Run: Invalid RSRenderNodeType!");
79 return false;
80 }
81 if (pixelmap == nullptr) {
82 RS_LOGE("RSSurfaceCaptureTask::Run: pixelmap == nullptr!");
83 return false;
84 }
85 #if defined(RS_ENABLE_GL) || defined(RS_ENABLE_VK)
86 auto renderContext = RSMainThread::Instance()->GetRenderEngine()->GetRenderContext();
87 Drawing::GPUContext* grContext = renderContext != nullptr ? renderContext->GetDrGPUContext() : nullptr;
88 RSTagTracker tagTracker(grContext, node->GetId(), RSTagTracker::TAGTYPE::TAG_CAPTURE, nodeName);
89 #endif
90 auto surface = CreateSurface(pixelmap, colorSpace);
91 if (surface == nullptr) {
92 RS_LOGE("RSSurfaceCaptureTask::Run: surface is nullptr!");
93 return false;
94 }
95 visitor_->SetSurface(surface.get());
96 node->Process(visitor_);
97 #if (defined (RS_ENABLE_GL) || defined (RS_ENABLE_VK)) && (defined RS_ENABLE_EGLIMAGE)
98 std::shared_ptr<Drawing::Image> img(surface.get()->GetImageSnapshot());
99 if (!img) {
100 RS_LOGE("RSSurfaceCaptureTask::Run: img is nullptr");
101 return false;
102 }
103 if (!CopyDataToPixelMap(img, pixelmap, colorSpace)) {
104 RS_LOGE("RSSurfaceCaptureTask::Run: CopyDataToPixelMap failed");
105 return false;
106 }
107 #endif
108 // To get dump image
109 // execute "param set rosen.dumpsurfacetype.enabled 3 && setenforce 0"
110 RSBaseRenderUtil::WritePixelMapToPng(*pixelmap);
111 if (callback) {
112 callback->OnSurfaceCapture(nodeId_, captureConfig_, pixelmap.get());
113 }
114 return true;
115 }
116
CreatePixelMapBySurfaceNode(std::shared_ptr<RSSurfaceRenderNode> node,bool isUniRender)117 std::unique_ptr<Media::PixelMap> RSSurfaceCaptureTask::CreatePixelMapBySurfaceNode(
118 std::shared_ptr<RSSurfaceRenderNode> node, bool isUniRender)
119 {
120 if (node == nullptr) {
121 RS_LOGE("RSSurfaceCaptureTask::CreatePixelMapBySurfaceNode: node == nullptr");
122 return nullptr;
123 }
124 if (!isUniRender && node->GetRSSurfaceHandler()->GetBuffer() == nullptr) {
125 RS_LOGE("RSSurfaceCaptureTask::CreatePixelMapBySurfaceNode: node GetBuffer == nullptr");
126 return nullptr;
127 }
128 const auto& property = node->GetRenderProperties();
129 int pixmapWidth = property.GetBoundsWidth();
130 int pixmapHeight = property.GetBoundsHeight();
131 Media::InitializationOptions opts;
132 opts.size.width = ceil(pixmapWidth * captureConfig_.scaleX);
133 opts.size.height = ceil(pixmapHeight * captureConfig_.scaleY);
134 RS_LOGD("RSSurfaceCaptureTask::CreatePixelMapBySurfaceNode: NodeId:[%{public}" PRIu64 "],"
135 " origin pixelmap width is [%{public}u], height is [%{public}u],"
136 " created pixelmap width is [%{public}u], height is [%{public}u],"
137 " the scale is scaleY:[%{public}f], scaleY:[%{public}f]",
138 node->GetId(), pixmapWidth, pixmapHeight, opts.size.width, opts.size.height,
139 captureConfig_.scaleX, captureConfig_.scaleY);
140 return Media::PixelMap::Create(opts);
141 }
142
CreatePixelMapByDisplayNode(std::shared_ptr<RSDisplayRenderNode> node,bool isUniRender)143 std::unique_ptr<Media::PixelMap> RSSurfaceCaptureTask::CreatePixelMapByDisplayNode(
144 std::shared_ptr<RSDisplayRenderNode> node, bool isUniRender)
145 {
146 if (node == nullptr) {
147 RS_LOGE("RSSurfaceCaptureTask::CreatePixelMapByDisplayNode: node is nullptr");
148 return nullptr;
149 }
150 uint64_t screenId = node->GetScreenId();
151 RSScreenModeInfo screenModeInfo;
152 sptr<RSScreenManager> screenManager = CreateOrGetScreenManager();
153 if (!screenManager) {
154 RS_LOGE("RSSurfaceCaptureTask::CreatePixelMapByDisplayNode: screenManager is nullptr!");
155 return nullptr;
156 }
157 auto screenInfo = screenManager->QueryScreenInfo(screenId);
158 uint32_t pixmapWidth = screenInfo.width;
159 uint32_t pixmapHeight = screenInfo.height;
160 if (!isUniRender) {
161 auto rotation = node->GetRotation();
162 if (rotation == ScreenRotation::ROTATION_90 || rotation == ScreenRotation::ROTATION_270) {
163 std::swap(pixmapWidth, pixmapHeight);
164 }
165 }
166 Media::InitializationOptions opts;
167 opts.size.width = ceil(pixmapWidth * captureConfig_.scaleX);
168 opts.size.height = ceil(pixmapHeight * captureConfig_.scaleY);
169 RS_LOGI("RSSurfaceCaptureTask::CreatePixelMapByDisplayNode: NodeId:[%{public}" PRIu64 "],"
170 " origin pixelmap width is [%{public}u], height is [%{public}u],"
171 " created pixelmap width is [%{public}u], height is [%{public}u],"
172 " the scale is scaleY:[%{public}f], scaleY:[%{public}f],",
173 node->GetId(), pixmapWidth, pixmapHeight, opts.size.width, opts.size.height,
174 captureConfig_.scaleX, captureConfig_.scaleY);
175 return Media::PixelMap::Create(opts);
176 }
177
CopyDataToPixelMap(std::shared_ptr<Drawing::Image> img,const std::unique_ptr<Media::PixelMap> & pixelmap,std::shared_ptr<Drawing::ColorSpace> colorSpace)178 bool CopyDataToPixelMap(std::shared_ptr<Drawing::Image> img, const std::unique_ptr<Media::PixelMap>& pixelmap,
179 std::shared_ptr<Drawing::ColorSpace> colorSpace)
180 {
181 if (!img || !pixelmap) {
182 RS_LOGE("RSSurfaceCaptureTask::CopyDataToPixelMap failed, img or pixelmap is nullptr");
183 return false;
184 }
185 auto size = pixelmap->GetRowBytes() * pixelmap->GetHeight();
186 #ifdef ROSEN_OHOS
187 int fd = AshmemCreate("RSSurfaceCapture Data", size);
188 if (fd < 0) {
189 RS_LOGE("RSSurfaceCaptureTask::CopyDataToPixelMap AshmemCreate fd < 0");
190 return false;
191 }
192 int result = AshmemSetProt(fd, PROT_READ | PROT_WRITE);
193 if (result < 0) {
194 RS_LOGE("RSSurfaceCaptureTask::CopyDataToPixelMap AshmemSetProt error");
195 ::close(fd);
196 return false;
197 }
198 void* ptr = ::mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
199 auto data = static_cast<uint8_t*>(ptr);
200 if (ptr == MAP_FAILED || ptr == nullptr) {
201 RS_LOGE("RSSurfaceCaptureTask::CopyDataToPixelMap data is nullptr");
202 ::close(fd);
203 return false;
204 }
205
206 Drawing::BitmapFormat format { Drawing::ColorType::COLORTYPE_RGBA_8888, Drawing::AlphaType::ALPHATYPE_PREMUL };
207 Drawing::Bitmap bitmap;
208 bitmap.Build(pixelmap->GetWidth(), pixelmap->GetHeight(), format, 0, colorSpace);
209 bitmap.SetPixels(data);
210 if (!img->ReadPixels(bitmap, 0, 0)) {
211 RS_LOGE("RSSurfaceCaptureTask::CopyDataToPixelMap readPixels failed");
212 ::close(fd);
213 return false;
214 }
215 void* fdPtr = new int32_t();
216 *static_cast<int32_t*>(fdPtr) = fd;
217 pixelmap->SetPixelsAddr(data, fdPtr, size, Media::AllocatorType::SHARE_MEM_ALLOC, nullptr);
218 #else
219 auto data = (uint8_t *)malloc(size);
220 if (data == nullptr) {
221 RS_LOGE("RSSurfaceCaptureTask::CopyDataToPixelMap data is nullptr");
222 return false;
223 }
224
225 Drawing::BitmapFormat format { Drawing::ColorType::COLORTYPE_RGBA_8888, Drawing::AlphaType::ALPHATYPE_PREMUL };
226 Drawing::Bitmap bitmap;
227 bitmap.Build(pixelmap->GetWidth(), pixelmap->GetHeight(), format, 0, colorSpace);
228 bitmap.SetPixels(data);
229 if (!img->ReadPixels(bitmap, 0, 0)) {
230 RS_LOGE("RSSurfaceCaptureTask::CopyDataToPixelMap readPixels failed");
231 free(data);
232 data = nullptr;
233 return false;
234 }
235
236 pixelmap->SetPixelsAddr(data, nullptr, size, Media::AllocatorType::HEAP_ALLOC, nullptr);
237 if (colorSpace != nullptr) {
238 pixelmap->InnerSetColorSpace(colorSpace->IsSRGB()?
239 OHOS::ColorManager::ColorSpace(OHOS::ColorManager::ColorSpaceName::SRGB):
240 OHOS::ColorManager::ColorSpace(OHOS::ColorManager::ColorSpaceName::DISPLAY_P3));
241 }
242 #endif
243 return true;
244 }
245
CreateSurface(const std::unique_ptr<Media::PixelMap> & pixelmap,std::shared_ptr<Drawing::ColorSpace> colorSpace)246 std::shared_ptr<Drawing::Surface> RSSurfaceCaptureTask::CreateSurface(
247 const std::unique_ptr<Media::PixelMap>& pixelmap, std::shared_ptr<Drawing::ColorSpace> colorSpace)
248 {
249 if (pixelmap == nullptr) {
250 RS_LOGE("RSSurfaceCaptureTask::CreateSurface: pixelmap == nullptr");
251 return nullptr;
252 }
253 auto address = const_cast<uint32_t*>(pixelmap->GetPixel32(0, 0));
254 if (address == nullptr) {
255 RS_LOGE("RSSurfaceCaptureTask::CreateSurface: address == nullptr");
256 return nullptr;
257 }
258 Drawing::ImageInfo info = Drawing::ImageInfo{pixelmap->GetWidth(), pixelmap->GetHeight(),
259 Drawing::ColorType::COLORTYPE_RGBA_8888, Drawing::AlphaType::ALPHATYPE_PREMUL, colorSpace};
260
261 #if (defined RS_ENABLE_GL) && (defined RS_ENABLE_EGLIMAGE)
262 if (RSSystemProperties::GetGpuApiType() == GpuApiType::OPENGL) {
263 auto renderContext = RSMainThread::Instance()->GetRenderEngine()->GetRenderContext();
264 if (renderContext == nullptr) {
265 RS_LOGE("RSSurfaceCaptureTask::CreateSurface: renderContext is nullptr");
266 return nullptr;
267 }
268 renderContext->SetUpGpuContext(nullptr);
269 return Drawing::Surface::MakeRenderTarget(renderContext->GetDrGPUContext(), false, info);
270 }
271 #endif
272 #ifdef RS_ENABLE_VK
273 if (RSSystemProperties::IsUseVulkan()) {
274 return Drawing::Surface::MakeRenderTarget(
275 RSMainThread::Instance()->GetRenderEngine()->GetSkContext().get(), false, info);
276 }
277 #endif
278 return Drawing::Surface::MakeRasterDirect(info, address, pixelmap->GetRowBytes());
279 }
280
RSSurfaceCaptureVisitor(const RSSurfaceCaptureConfig & captureConfig,bool isUniRender)281 RSSurfaceCaptureVisitor::RSSurfaceCaptureVisitor(const RSSurfaceCaptureConfig& captureConfig, bool isUniRender)
282 : captureConfig_(captureConfig), isUniRender_(isUniRender)
283 {
284 renderEngine_ = RSMainThread::Instance()->GetRenderEngine();
285 }
286
SetSurface(Drawing::Surface * surface)287 void RSSurfaceCaptureVisitor::SetSurface(Drawing::Surface* surface)
288 {
289 if (surface == nullptr) {
290 RS_LOGE("RSSurfaceCaptureVisitor::SetSurface: surface == nullptr");
291 return;
292 }
293 canvas_ = std::make_unique<RSPaintFilterCanvas>(surface);
294 canvas_->Scale(captureConfig_.scaleX, captureConfig_.scaleY);
295 canvas_->SetDisableFilterCache(true);
296 }
297
ProcessChildren(RSRenderNode & node)298 void RSSurfaceCaptureVisitor::ProcessChildren(RSRenderNode &node)
299 {
300 for (auto& child : *node.GetSortedChildren()) {
301 if (!child) {
302 continue;
303 }
304 child->Process(shared_from_this());
305 }
306 }
307
ProcessDisplayRenderNode(RSDisplayRenderNode & node)308 void RSSurfaceCaptureVisitor::ProcessDisplayRenderNode(RSDisplayRenderNode &node)
309 {
310 RS_TRACE_NAME("RSSurfaceCaptureVisitor::ProcessDisplayRenderNode:" +
311 std::to_string(node.GetId()));
312 RS_LOGD("RSSurfaceCaptureVisitor::ProcessDisplayRenderNode child size:[%{public}d] total",
313 node.GetChildrenCount());
314
315 if (canvas_ == nullptr) {
316 RS_LOGE("RSSurfaceCaptureVisitor::ProcessDisplayRenderNode: Canvas is null!");
317 return;
318 }
319
320 ProcessChildren(node);
321 }
322
CaptureSingleSurfaceNodeWithoutUni(RSSurfaceRenderNode & node)323 void RSSurfaceCaptureVisitor::CaptureSingleSurfaceNodeWithoutUni(RSSurfaceRenderNode& node)
324 {
325 Drawing::Matrix translateMatrix;
326 auto parentPtr = node.GetParent().lock();
327 if (parentPtr != nullptr && parentPtr->IsInstanceOf<RSSurfaceRenderNode>()) {
328 // calculate the offset from this node's parent, and perform translate.
329 auto parentNode = std::static_pointer_cast<RSSurfaceRenderNode>(parentPtr);
330 const float parentNodeTranslateX = parentNode->GetTotalMatrix().Get(Drawing::Matrix::Index::TRANS_X);
331 const float parentNodeTranslateY = parentNode->GetTotalMatrix().Get(Drawing::Matrix::Index::TRANS_Y);
332 const float thisNodetranslateX = node.GetTotalMatrix().Get(Drawing::Matrix::Index::TRANS_X);
333 const float thisNodetranslateY = node.GetTotalMatrix().Get(Drawing::Matrix::Index::TRANS_Y);
334 translateMatrix.PreTranslate(
335 thisNodetranslateX - parentNodeTranslateX, thisNodetranslateY - parentNodeTranslateY);
336 }
337 if (node.GetSpecialLayerMgr().Find(SpecialLayerType::SECURITY) ||
338 node.GetSpecialLayerMgr().Find(SpecialLayerType::SKIP)) {
339 RS_LOGD("RSSurfaceCaptureVisitor::CaptureSingleSurfaceNodeWithoutUni: \
340 process RSSurfaceRenderNode(id:[%{public}" PRIu64 "]) clear white since it is security layer.",
341 node.GetId());
342 Drawing::AutoCanvasRestore acr(*canvas_.get(), true);
343 canvas_->ConcatMatrix(translateMatrix);
344 canvas_->Clear(Drawing::Color::COLOR_WHITE);
345 return;
346 }
347
348 if (node.GetChildrenCount() > 0) {
349 canvas_->ConcatMatrix(translateMatrix);
350 const auto saveCnt = canvas_->Save();
351 ProcessChildren(node);
352 canvas_->RestoreToCount(saveCnt);
353 if (node.GetRSSurfaceHandler()->GetBuffer() != nullptr) {
354 // in node's local coordinate.
355 auto params = RSDividedRenderUtil::CreateBufferDrawParam(node, true, false, false, false);
356 renderEngine_->DrawSurfaceNodeWithParams(*canvas_, node, params);
357 }
358 } else {
359 Drawing::AutoCanvasRestore acr(*canvas_.get(), true);
360 canvas_->ConcatMatrix(translateMatrix);
361 if (node.GetRSSurfaceHandler()->GetBuffer() != nullptr) {
362 // in node's local coordinate.
363 auto params = RSDividedRenderUtil::CreateBufferDrawParam(node, true, false, false, false);
364 renderEngine_->DrawSurfaceNodeWithParams(*canvas_, node, params);
365 }
366 }
367 }
368
CaptureSurfaceInDisplayWithoutUni(RSSurfaceRenderNode & node)369 void RSSurfaceCaptureVisitor::CaptureSurfaceInDisplayWithoutUni(RSSurfaceRenderNode& node)
370 {
371 if (node.GetSpecialLayerMgr().Find(SpecialLayerType::SECURITY) ||
372 node.GetSpecialLayerMgr().Find(SpecialLayerType::SKIP)) {
373 RS_LOGD("RSSurfaceCaptureVisitor::CaptureSurfaceInDisplayWithoutUni: \
374 process RSSurfaceRenderNode(id:[%{public}" PRIu64 "]) paused since it is security layer.",
375 node.GetId());
376 return;
377 }
378 ProcessChildren(node);
379 if (node.GetRSSurfaceHandler()->GetBuffer() != nullptr) {
380 // in display's coordinate.
381 auto params = RSDividedRenderUtil::CreateBufferDrawParam(node, false, false, false, false);
382 renderEngine_->DrawSurfaceNodeWithParams(*canvas_, node, params);
383 }
384 }
385
ProcessSurfaceRenderNodeWithoutUni(RSSurfaceRenderNode & node)386 void RSSurfaceCaptureVisitor::ProcessSurfaceRenderNodeWithoutUni(RSSurfaceRenderNode& node)
387 {
388 if (isDisplayNode_) {
389 CaptureSurfaceInDisplayWithoutUni(node);
390 } else {
391 CaptureSingleSurfaceNodeWithoutUni(node);
392 }
393 }
394
ProcessSurfaceRenderNode(RSSurfaceRenderNode & node)395 void RSSurfaceCaptureVisitor::ProcessSurfaceRenderNode(RSSurfaceRenderNode &node)
396 {
397 RS_TRACE_NAME("RSSurfaceCaptureVisitor::Process:" + node.GetName());
398
399 if (canvas_ == nullptr) {
400 RS_LOGE("RSSurfaceCaptureVisitor::ProcessSurfaceRenderNode, canvas is nullptr");
401 return;
402 }
403
404 if (!node.ShouldPaint()) {
405 RS_LOGD("RSSurfaceCaptureVisitor::ProcessSurfaceRenderNode node: %{public}" PRIu64 " invisible", node.GetId());
406 return;
407 }
408
409 ProcessSurfaceRenderNodeWithoutUni(node);
410 }
411 } // namespace Rosen
412 } // namespace OHOS
413