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 "pipeline/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/rs_base_render_node.h"
30 #include "pipeline/rs_canvas_drawing_render_node.h"
31 #include "pipeline/rs_composer_adapter.h"
32 #include "pipeline/rs_display_render_node.h"
33 #include "pipeline/rs_divided_render_util.h"
34 #include "pipeline/rs_effect_render_node.h"
35 #include "pipeline/rs_main_thread.h"
36 #include "pipeline/rs_render_service_connection.h"
37 #include "pipeline/rs_root_render_node.h"
38 #include "pipeline/rs_surface_render_node.h"
39 #include "pipeline/rs_uni_render_judgement.h"
40 #include "pipeline/rs_uni_render_util.h"
41 #include "platform/common/rs_log.h"
42 #include "platform/drawing/rs_surface.h"
43 #include "render/rs_drawing_filter.h"
44 #include "render/rs_skia_filter.h"
45 #include "rs_base_render_engine.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_, 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     if (colorSpace != nullptr) {
219         pixelmap->InnerSetColorSpace(colorSpace->IsSRGB()?
220             OHOS::ColorManager::ColorSpace(OHOS::ColorManager::ColorSpaceName::SRGB) :
221             OHOS::ColorManager::ColorSpace(OHOS::ColorManager::ColorSpaceName::DISPLAY_P3));
222     }
223 #else
224     auto data = (uint8_t *)malloc(size);
225     if (data == nullptr) {
226         RS_LOGE("RSSurfaceCaptureTask::CopyDataToPixelMap data is nullptr");
227         return false;
228     }
229 
230     Drawing::BitmapFormat format { Drawing::ColorType::COLORTYPE_RGBA_8888, Drawing::AlphaType::ALPHATYPE_PREMUL };
231     Drawing::Bitmap bitmap;
232     bitmap.Build(pixelmap->GetWidth(), pixelmap->GetHeight(), format, 0, colorSpace);
233     bitmap.SetPixels(data);
234     if (!img->ReadPixels(bitmap, 0, 0)) {
235         RS_LOGE("RSSurfaceCaptureTask::CopyDataToPixelMap readPixels failed");
236         free(data);
237         data = nullptr;
238         return false;
239     }
240 
241     pixelmap->SetPixelsAddr(data, nullptr, size, Media::AllocatorType::HEAP_ALLOC, nullptr);
242     if (colorSpace != nullptr) {
243         pixelmap->InnerSetColorSpace(colorSpace->IsSRGB()?
244             OHOS::ColorManager::ColorSpace(OHOS::ColorManager::ColorSpaceName::SRGB) :
245             OHOS::ColorManager::ColorSpace(OHOS::ColorManager::ColorSpaceName::DISPLAY_P3));
246     }
247 #endif
248     return true;
249 }
250 
CreateSurface(const std::unique_ptr<Media::PixelMap> & pixelmap,std::shared_ptr<Drawing::ColorSpace> colorSpace)251 std::shared_ptr<Drawing::Surface> RSSurfaceCaptureTask::CreateSurface(
252     const std::unique_ptr<Media::PixelMap>& pixelmap, std::shared_ptr<Drawing::ColorSpace> colorSpace)
253 {
254     if (pixelmap == nullptr) {
255         RS_LOGE("RSSurfaceCaptureTask::CreateSurface: pixelmap == nullptr");
256         return nullptr;
257     }
258     auto address = const_cast<uint32_t*>(pixelmap->GetPixel32(0, 0));
259     if (address == nullptr) {
260         RS_LOGE("RSSurfaceCaptureTask::CreateSurface: address == nullptr");
261         return nullptr;
262     }
263     Drawing::ImageInfo info = Drawing::ImageInfo{pixelmap->GetWidth(), pixelmap->GetHeight(),
264         Drawing::ColorType::COLORTYPE_RGBA_8888, Drawing::AlphaType::ALPHATYPE_PREMUL, colorSpace};
265 
266 #if (defined RS_ENABLE_GL) && (defined RS_ENABLE_EGLIMAGE)
267     if (RSSystemProperties::GetGpuApiType() == GpuApiType::OPENGL) {
268         auto renderContext = RSMainThread::Instance()->GetRenderEngine()->GetRenderContext();
269         if (renderContext == nullptr) {
270             RS_LOGE("RSSurfaceCaptureTask::CreateSurface: renderContext is nullptr");
271             return nullptr;
272         }
273         renderContext->SetUpGpuContext(nullptr);
274         return Drawing::Surface::MakeRenderTarget(renderContext->GetDrGPUContext(), false, info);
275     }
276 #endif
277 #ifdef RS_ENABLE_VK
278     if (RSSystemProperties::IsUseVulkan()) {
279         return Drawing::Surface::MakeRenderTarget(
280             RSMainThread::Instance()->GetRenderEngine()->GetSkContext().get(), false, info);
281     }
282 #endif
283     return Drawing::Surface::MakeRasterDirect(info, address, pixelmap->GetRowBytes());
284 }
285 
RSSurfaceCaptureVisitor(const RSSurfaceCaptureConfig & captureConfig,bool isUniRender)286 RSSurfaceCaptureVisitor::RSSurfaceCaptureVisitor(const RSSurfaceCaptureConfig& captureConfig, bool isUniRender)
287     : captureConfig_(captureConfig), isUniRender_(isUniRender)
288 {
289     renderEngine_ = RSMainThread::Instance()->GetRenderEngine();
290 }
291 
SetSurface(Drawing::Surface * surface)292 void RSSurfaceCaptureVisitor::SetSurface(Drawing::Surface* surface)
293 {
294     if (surface == nullptr) {
295         RS_LOGE("RSSurfaceCaptureVisitor::SetSurface: surface == nullptr");
296         return;
297     }
298     canvas_ = std::make_unique<RSPaintFilterCanvas>(surface);
299     canvas_->Scale(captureConfig_.scaleX, captureConfig_.scaleY);
300     canvas_->SetDisableFilterCache(true);
301 }
302 
ProcessChildren(RSRenderNode & node)303 void RSSurfaceCaptureVisitor::ProcessChildren(RSRenderNode &node)
304 {
305     for (auto& child : *node.GetSortedChildren()) {
306         if (!child) {
307             continue;
308         }
309         child->Process(shared_from_this());
310     }
311 }
312 
ProcessDisplayRenderNode(RSDisplayRenderNode & node)313 void RSSurfaceCaptureVisitor::ProcessDisplayRenderNode(RSDisplayRenderNode &node)
314 {
315     RS_TRACE_NAME("RSSurfaceCaptureVisitor::ProcessDisplayRenderNode:" +
316         std::to_string(node.GetId()));
317     RS_LOGD("RSSurfaceCaptureVisitor::ProcessDisplayRenderNode child size:[%{public}d] total",
318         node.GetChildrenCount());
319 
320     if (canvas_ == nullptr) {
321         RS_LOGE("RSSurfaceCaptureVisitor::ProcessDisplayRenderNode: Canvas is null!");
322         return;
323     }
324 
325     ProcessChildren(node);
326 }
327 
CaptureSingleSurfaceNodeWithoutUni(RSSurfaceRenderNode & node)328 void RSSurfaceCaptureVisitor::CaptureSingleSurfaceNodeWithoutUni(RSSurfaceRenderNode& node)
329 {
330     Drawing::Matrix translateMatrix;
331     auto parentPtr = node.GetParent().lock();
332     if (parentPtr != nullptr && parentPtr->IsInstanceOf<RSSurfaceRenderNode>()) {
333         // calculate the offset from this node's parent, and perform translate.
334         auto parentNode = std::static_pointer_cast<RSSurfaceRenderNode>(parentPtr);
335         const float parentNodeTranslateX = parentNode->GetTotalMatrix().Get(Drawing::Matrix::Index::TRANS_X);
336         const float parentNodeTranslateY = parentNode->GetTotalMatrix().Get(Drawing::Matrix::Index::TRANS_Y);
337         const float thisNodetranslateX = node.GetTotalMatrix().Get(Drawing::Matrix::Index::TRANS_X);
338         const float thisNodetranslateY = node.GetTotalMatrix().Get(Drawing::Matrix::Index::TRANS_Y);
339         translateMatrix.PreTranslate(
340             thisNodetranslateX - parentNodeTranslateX, thisNodetranslateY - parentNodeTranslateY);
341     }
342     if (node.GetSecurityLayer() || node.GetSkipLayer()) {
343         RS_LOGD("RSSurfaceCaptureVisitor::CaptureSingleSurfaceNodeWithoutUni: \
344             process RSSurfaceRenderNode(id:[%{public}" PRIu64 "]) clear white since it is security layer.",
345             node.GetId());
346         Drawing::AutoCanvasRestore acr(*canvas_.get(), true);
347         canvas_->ConcatMatrix(translateMatrix);
348         canvas_->Clear(Drawing::Color::COLOR_WHITE);
349         return;
350     }
351 
352     if (node.GetChildrenCount() > 0) {
353         canvas_->ConcatMatrix(translateMatrix);
354         const auto saveCnt = canvas_->Save();
355         ProcessChildren(node);
356         canvas_->RestoreToCount(saveCnt);
357         if (node.GetRSSurfaceHandler()->GetBuffer() != nullptr) {
358             // in node's local coordinate.
359             auto params = RSDividedRenderUtil::CreateBufferDrawParam(node, true, false, false, false);
360             renderEngine_->DrawSurfaceNodeWithParams(*canvas_, node, params);
361         }
362     } else {
363         Drawing::AutoCanvasRestore acr(*canvas_.get(), true);
364         canvas_->ConcatMatrix(translateMatrix);
365         if (node.GetRSSurfaceHandler()->GetBuffer() != nullptr) {
366             // in node's local coordinate.
367             auto params = RSDividedRenderUtil::CreateBufferDrawParam(node, true, false, false, false);
368             renderEngine_->DrawSurfaceNodeWithParams(*canvas_, node, params);
369         }
370     }
371 }
372 
CaptureSurfaceInDisplayWithoutUni(RSSurfaceRenderNode & node)373 void RSSurfaceCaptureVisitor::CaptureSurfaceInDisplayWithoutUni(RSSurfaceRenderNode& node)
374 {
375     if (node.GetSecurityLayer() || node.GetSkipLayer()) {
376         RS_LOGD("RSSurfaceCaptureVisitor::CaptureSurfaceInDisplayWithoutUni: \
377             process RSSurfaceRenderNode(id:[%{public}" PRIu64 "]) paused since it is security layer.",
378             node.GetId());
379         return;
380     }
381     ProcessChildren(node);
382     if (node.GetRSSurfaceHandler()->GetBuffer() != nullptr) {
383         // in display's coordinate.
384         auto params = RSDividedRenderUtil::CreateBufferDrawParam(node, false, false, false, false);
385         renderEngine_->DrawSurfaceNodeWithParams(*canvas_, node, params);
386     }
387 }
388 
ProcessSurfaceRenderNodeWithoutUni(RSSurfaceRenderNode & node)389 void RSSurfaceCaptureVisitor::ProcessSurfaceRenderNodeWithoutUni(RSSurfaceRenderNode& node)
390 {
391     if (isDisplayNode_) {
392         CaptureSurfaceInDisplayWithoutUni(node);
393     } else {
394         CaptureSingleSurfaceNodeWithoutUni(node);
395     }
396 }
397 
ProcessSurfaceRenderNode(RSSurfaceRenderNode & node)398 void RSSurfaceCaptureVisitor::ProcessSurfaceRenderNode(RSSurfaceRenderNode &node)
399 {
400     RS_TRACE_NAME("RSSurfaceCaptureVisitor::Process:" + node.GetName());
401 
402     if (canvas_ == nullptr) {
403         RS_LOGE("RSSurfaceCaptureVisitor::ProcessSurfaceRenderNode, canvas is nullptr");
404         return;
405     }
406 
407     if (!node.ShouldPaint()) {
408         RS_LOGD("RSSurfaceCaptureVisitor::ProcessSurfaceRenderNode node: %{public}" PRIu64 " invisible", node.GetId());
409         return;
410     }
411     ProcessSurfaceRenderNodeWithoutUni(node);
412 }
413 } // namespace Rosen
414 } // namespace OHOS
415