• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2025 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_ui_capture_solo_task_parallel.h"
17 
18 #include <memory>
19 #include <parameters.h>
20 #include <sys/mman.h>
21 
22 #include "draw/surface.h"
23 #include "draw/color.h"
24 
25 #include "rs_trace.h"
26 
27 #include "common/rs_background_thread.h"
28 #include "common/rs_obj_abs_geometry.h"
29 #include "drawable/rs_canvas_render_node_drawable.h"
30 #include "feature/capture/rs_surface_capture_task_parallel.h"
31 #include "feature/uifirst/rs_uifirst_manager.h"
32 #include "feature_cfg/graphic_feature_param_manager.h"
33 #include "memory/rs_tag_tracker.h"
34 #include "params/rs_surface_render_params.h"
35 #include "pipeline/main_thread/rs_main_thread.h"
36 #include "pipeline/main_thread/rs_render_service_connection.h"
37 #include "pipeline/render_thread/rs_uni_render_util.h"
38 #include "pipeline/rs_base_render_node.h"
39 #include "pipeline/rs_canvas_render_node.h"
40 #include "pipeline/rs_paint_filter_canvas.h"
41 #include "pipeline/rs_surface_render_node.h"
42 #include "pipeline/rs_uni_render_judgement.h"
43 #include "platform/common/rs_log.h"
44 #include "platform/drawing/rs_surface.h"
45 #include "render/rs_drawing_filter.h"
46 #include "render/rs_skia_filter.h"
47 #include "screen_manager/rs_screen_manager.h"
48 #include "screen_manager/rs_screen_mode_info.h"
49 
50 #ifdef RS_ENABLE_VK
51 #include "platform/ohos/backend/native_buffer_utils.h"
52 #endif
53 
54 namespace OHOS {
55 namespace Rosen {
56 
CaptureSoloNode(NodeId id,const RSSurfaceCaptureConfig & captureConfig)57 std::vector<std::pair<NodeId, std::shared_ptr<Media::PixelMap>>> RSUiCaptureSoloTaskParallel::CaptureSoloNode(
58     NodeId id, const RSSurfaceCaptureConfig& captureConfig)
59 {
60     std::vector<std::pair<NodeId, std::shared_ptr<Media::PixelMap>>> pixelMapIdPairVector;
61     std::vector<NodeId> nodeIdVec;
62     std::shared_ptr<RSBaseRenderNode> instanceRootNode =
63         RSMainThread::Instance()->GetContext().GetNodeMap().GetRenderNode(id);
64     if (!instanceRootNode) {
65         RS_LOGE("RSUiCaptureSoloTaskParallel::CaptureSoloNode RootNodeId:[%{public}" PRIu64 "] is nullptr", id);
66         return pixelMapIdPairVector;
67     }
68     instanceRootNode->CollectAllChildren(instanceRootNode, nodeIdVec);
69     for (auto nodeId : nodeIdVec) {
70         std::unique_ptr<Media::PixelMap> soloPixelMap = CaptureSoloNodePixelMap(nodeId, captureConfig);
71         if (!soloPixelMap) {
72             RS_LOGE("RSUiCaptureSoloTaskParallel::CaptureSoloNode nodeId:[%{public}" PRIu64 "], "
73                 "soloPixelMap is nullptr", nodeId);
74         }
75         std::shared_ptr<Media::PixelMap> soloPixelMapShared(std::move(soloPixelMap));
76         pixelMapIdPairVector.push_back(std::make_pair(nodeId, soloPixelMapShared));
77     }
78     return pixelMapIdPairVector;
79 }
80 
CaptureSoloNodePixelMap(NodeId id,const RSSurfaceCaptureConfig & captureConfig)81 std::unique_ptr<Media::PixelMap> RSUiCaptureSoloTaskParallel::CaptureSoloNodePixelMap(NodeId id,
82     const RSSurfaceCaptureConfig& captureConfig)
83 {
84     RS_LOGI("RSUiCaptureSoloTaskParallel::CaptureSoloNodePixelMap nodeId:[%{public}" PRIu64 "]", id);
85     std::shared_ptr<RSUiCaptureSoloTaskParallel> captureHandle =
86         std::make_shared<RSUiCaptureSoloTaskParallel>(id, captureConfig);
87     if (captureHandle == nullptr) {
88         RS_LOGE("RSUiCaptureSoloTaskParallel::CaptureSoloNodePixelMap captureHandle is nullptr!");
89         return nullptr;
90     }
91     if (!captureHandle->CreateResources()) {
92         RS_LOGE("RSUiCaptureSoloTaskParallel::CaptureSoloNodePixelMap CreateResources failed");
93         return nullptr;
94     }
95     std::function<void()> captureTask = [captureHandle]() -> void {
96         RSSystemProperties::SetForceHpsBlurDisabled(true);
97         if (!captureHandle->Run()) {
98             RS_LOGE("RSUiCaptureSoloTaskParallel::CaptureSoloNodePixelMap Run failed");
99             captureHandle->pixelMap_ = nullptr;
100         }
101         RSSystemProperties::SetForceHpsBlurDisabled(false);
102     };
103     RSUniRenderThread::Instance().PostSyncTask(captureTask);
104     if (captureHandle->pixelMap_ == nullptr) {
105         RS_LOGD("RSUiCaptureSoloTaskParallel::CaptureSoloNodePixelMap pixelMap_ is nullptr");
106     }
107     return std::move(captureHandle->pixelMap_);
108 }
109 
CreateResources()110 bool RSUiCaptureSoloTaskParallel::CreateResources()
111 {
112     if (ROSEN_EQ(captureConfig_.scaleX, 0.f) || ROSEN_EQ(captureConfig_.scaleY, 0.f) ||
113         captureConfig_.scaleX < 0.f || captureConfig_.scaleY < 0.f) {
114         RS_LOGE("RSUiCaptureSoloTaskParallel::CreateResources: SurfaceCapture scale is invalid.");
115         return false;
116     }
117     auto node = RSMainThread::Instance()->GetContext().GetNodeMap().GetRenderNode(nodeId_);
118     if (node == nullptr) {
119         RS_LOGE("RSUiCaptureSoloTaskParallel::CreateResources: Invalid nodeId:[%{public}" PRIu64 "]",
120             nodeId_);
121         return false;
122     }
123     if (node->GetType() == RSRenderNodeType::UNKNOW) {
124         RS_LOGE("RSUiCaptureSoloTaskParallel::CreateResources: nodeId:[%{public}" PRIu64 "]"
125             " RSRenderNodeType is UNKNOW", nodeId_);
126         return false;
127     }
128 #ifdef RS_ENABLE_VK
129     float nodeBoundsWidth = node->GetRenderProperties().GetBoundsWidth();
130     float nodeBoundsHeight = node->GetRenderProperties().GetBoundsHeight();
131     int32_t width = ceil(nodeBoundsWidth * captureConfig_.scaleX);
132     int32_t height = ceil(nodeBoundsHeight * captureConfig_.scaleY);
133     if (width > 0 && static_cast<int32_t>(OHOS::Rosen::NativeBufferUtils::VKIMAGE_LIMIT_SIZE) / width < height) {
134         RS_LOGE("RSUiCaptureSoloTaskParallel::CreateResources: image is too large,"
135             " width:%{public}d, height::%{public}d", width, height);
136         return false;
137     }
138     RS_LOGD("RSUiCaptureSoloTaskParallel::CreateResources: Origin nodeBoundsWidth is [%{public}f,]"
139         " Origin nodeBoundsHeight is [%{public}f]", nodeBoundsWidth, nodeBoundsHeight);
140 #endif
141     if (auto surfaceNode = node->ReinterpretCastTo<RSSurfaceRenderNode>()) {
142         nodeDrawable_ = std::static_pointer_cast<DrawableV2::RSRenderNodeDrawable>(
143             DrawableV2::RSRenderNodeDrawableAdapter::OnGenerate(surfaceNode));
144         pixelMap_ = CreatePixelMapByNode(surfaceNode);
145     } else if (auto canvasNode = node->ReinterpretCastTo<RSCanvasRenderNode>()) {
146         nodeDrawable_ = std::static_pointer_cast<DrawableV2::RSRenderNodeDrawable>(
147             DrawableV2::RSRenderNodeDrawableAdapter::OnGenerate(canvasNode));
148         pixelMap_ = CreatePixelMapByNode(canvasNode);
149     } else if (auto effectNode = node->ReinterpretCastTo<RSEffectRenderNode>()) {
150         nodeDrawable_ = std::static_pointer_cast<DrawableV2::RSRenderNodeDrawable>(
151             DrawableV2::RSRenderNodeDrawableAdapter::OnGenerate(effectNode));
152         pixelMap_ = CreatePixelMapByNode(effectNode);
153     } else if (node->GetType() == RSRenderNodeType::CANVAS_DRAWING_NODE ||
154         node->GetType() == RSRenderNodeType::ROOT_NODE) {
155         nodeDrawable_ = std::static_pointer_cast<DrawableV2::RSRenderNodeDrawable>(
156             DrawableV2::RSRenderNodeDrawableAdapter::OnGenerate(node));
157         pixelMap_ = CreatePixelMapByNode(node);
158     } else {
159         RS_LOGE("RSUiCaptureSoloTaskParallel::CreateResources: nodeId:[%{public}" PRIu64 "]"
160             " RSRenderNodeType is invalid", nodeId_);
161         return false;
162     }
163     if (pixelMap_ == nullptr) {
164         RS_LOGE("RSUiCaptureSoloTaskParallel::CreateResources: pixelMap_ is nullptr");
165         return false;
166     }
167     return true;
168 }
169 
Run()170 bool RSUiCaptureSoloTaskParallel::Run()
171 {
172     RS_TRACE_NAME_FMT("RSUiCaptureSoloTaskParallel::TakeSurfaceCaptureSolo. NodeId: [%" PRIu64 "], from pid: [%d]",
173         nodeId_, ExtractPid(nodeId_));
174 
175 #if defined(RS_ENABLE_GL) || defined(RS_ENABLE_VK)
176     auto renderContext = RSUniRenderThread::Instance().GetRenderEngine()->GetRenderContext();
177     auto grContext = renderContext != nullptr ? renderContext->GetDrGPUContext() : nullptr;
178     std::string nodeName("RSUiCaptureSoloTaskParallel");
179     RSTagTracker tagTracker(renderContext != nullptr ? renderContext->GetSharedDrGPUContext() : nullptr,
180         nodeId_, RSTagTracker::TAGTYPE::TAG_CAPTURE, nodeName);
181 #endif
182     auto surface = CreateSurface(pixelMap_);
183     if (surface == nullptr) {
184         RS_LOGE("RSUiCaptureSoloTaskParallel::Run: surface is nullptr!");
185         return false;
186     }
187     if (!nodeDrawable_) {
188         RS_LOGE("RSUiCaptureSoloTaskParallel::Run: Invalid RSRenderNodeDrawable!");
189         return false;
190     }
191 
192     RSPaintFilterCanvas canvas(surface.get());
193     canvas.Scale(captureConfig_.scaleX, captureConfig_.scaleY);
194     canvas.SetDisableFilterCache(true);
195     canvas.SetUICapture(true);
196     const auto& nodeParams = nodeDrawable_->GetRenderParams();
197     if (UNLIKELY(!nodeParams)) {
198         RS_LOGE("RSUiCaptureSoloTaskParallel::Run: RenderParams is nullptr!");
199         return false;
200     }
201     Drawing::Matrix relativeMatrix = Drawing::Matrix();
202     relativeMatrix.Set(Drawing::Matrix::Index::SCALE_X, captureConfig_.scaleX);
203     relativeMatrix.Set(Drawing::Matrix::Index::SCALE_Y, captureConfig_.scaleY);
204     Drawing::Matrix invertMatrix;
205     if (nodeParams->GetMatrix().Invert(invertMatrix)) {
206         relativeMatrix.PreConcat(invertMatrix);
207     }
208     canvas.SetMatrix(relativeMatrix);
209 
210     RSUniRenderThread::SetCaptureParam(CaptureParam(true, true, false, false, false, false, false, true));
211     nodeDrawable_->OnCapture(canvas);
212     RSUniRenderThread::ResetCaptureParam();
213 
214 #if (defined (RS_ENABLE_GL) || defined (RS_ENABLE_VK)) && (defined RS_ENABLE_EGLIMAGE)
215 #ifdef RS_ENABLE_UNI_RENDER
216     RSUniRenderUtil::OptimizedFlushAndSubmit(surface, grContext, GetFeatureParamValue("UICaptureConfig",
217         &UICaptureParam::IsUseOptimizedFlushAndSubmitEnabled).value_or(false));
218     bool snapshotDmaEnabled = system::GetBoolParameter("rosen.snapshotDma.enabled", true);
219     bool isEnableFeature = GetFeatureParamValue("CaptureConfig",
220         &CaptureBaseParam::IsSnapshotWithDMAEnabled).value_or(false);
221     if (snapshotDmaEnabled && isEnableFeature) {
222         auto copytask =
223             RSUiCaptureSoloTaskParallel::CreateSurfaceSyncCopyTask(
224                 surface, pixelMap_, nodeId_, captureConfig_);
225         if (!copytask) {
226             RS_LOGE("RSUiCaptureSoloTaskParallel::Run: create capture task failed!");
227             return false;
228         }
229         RSBackgroundThread::Instance().PostSyncTask(copytask);
230         return true;
231     } else {
232         std::shared_ptr<Drawing::Image> img(surface.get()->GetImageSnapshot());
233         if (!img) {
234             RS_LOGE("RSUiCaptureSoloTaskParallel::Run: img is nullptr");
235             return false;
236         }
237         if (!CopyDataToPixelMap(img, pixelMap_)) {
238             RS_LOGE("RSUiCaptureSoloTaskParallel::Run: CopyDataToPixelMap failed");
239             return false;
240         }
241     }
242 #endif
243 #endif
244     // To get dump image
245     // execute "param set rosen.dumpsurfacetype.enabled 3 && setenforce 0"
246     RSBaseRenderUtil::WritePixelMapToPng(*pixelMap_);
247     RS_LOGI("RSUiCaptureSoloTaskParallel::CaptureSoloNodePixelMap capture success nodeId:[%{public}" PRIu64
248         "], pixelMap width: %{public}d, height: %{public}d",
249         nodeId_, pixelMap_->GetWidth(), pixelMap_->GetHeight());
250     return true;
251 }
252 
CreatePixelMapByNode(std::shared_ptr<RSRenderNode> node) const253 std::unique_ptr<Media::PixelMap> RSUiCaptureSoloTaskParallel::CreatePixelMapByNode(
254     std::shared_ptr<RSRenderNode> node) const
255 {
256     float pixmapWidth = node->GetRenderProperties().GetBoundsWidth();
257     float pixmapHeight = node->GetRenderProperties().GetBoundsHeight();
258     Media::InitializationOptions opts;
259     opts.size.width = ceil(pixmapWidth * captureConfig_.scaleX);
260     opts.size.height = ceil(pixmapHeight * captureConfig_.scaleY);
261     RS_LOGD("RSUiCaptureSoloTaskParallel::CreatePixelMapByNode: NodeId:[%{public}" PRIu64 "],"
262         " origin pixelmap width is [%{public}f], height is [%{public}f],"
263         " created pixelmap width is [%{public}u], height is [%{public}u],"
264         " the scale is scaleX:[%{public}f], scaleY:[%{public}f]",
265         node->GetId(), pixmapWidth, pixmapHeight, opts.size.width, opts.size.height,
266         captureConfig_.scaleX, captureConfig_.scaleY);
267     return Media::PixelMap::Create(opts);
268 }
269 
CreateSurface(const std::unique_ptr<Media::PixelMap> & pixelmap) const270 std::shared_ptr<Drawing::Surface> RSUiCaptureSoloTaskParallel::CreateSurface(
271     const std::unique_ptr<Media::PixelMap>& pixelmap) const
272 {
273     if (pixelmap == nullptr) {
274         RS_LOGE("RSUiCaptureSoloTaskParallel::CreateSurface: pixelmap == nullptr");
275         return nullptr;
276     }
277     auto address = const_cast<uint32_t*>(pixelmap->GetPixel32(0, 0));
278     if (address == nullptr) {
279         RS_LOGE("RSUiCaptureSoloTaskParallel::CreateSurface: address == nullptr");
280         return nullptr;
281     }
282     Drawing::ImageInfo info = Drawing::ImageInfo{pixelmap->GetWidth(), pixelmap->GetHeight(),
283         Drawing::ColorType::COLORTYPE_RGBA_8888, Drawing::AlphaType::ALPHATYPE_PREMUL};
284 
285 #if (defined RS_ENABLE_GL) && (defined RS_ENABLE_EGLIMAGE)
286     if (RSSystemProperties::GetGpuApiType() == GpuApiType::OPENGL) {
287         auto renderContext = RSUniRenderThread::Instance().GetRenderEngine()->GetRenderContext();
288         if (renderContext == nullptr) {
289             RS_LOGE("RSUiCaptureSoloTaskParallel::CreateSurface: renderContext is nullptr");
290             return nullptr;
291         }
292         renderContext->SetUpGpuContext(nullptr);
293         return Drawing::Surface::MakeRenderTarget(renderContext->GetDrGPUContext(), false, info);
294     }
295 #endif
296 #ifdef RS_ENABLE_VK
297     if (RSSystemProperties::GetGpuApiType() == GpuApiType::VULKAN ||
298         RSSystemProperties::GetGpuApiType() == GpuApiType::DDGR) {
299         return Drawing::Surface::MakeRenderTarget(
300             RSUniRenderThread::Instance().GetRenderEngine()->GetSkContext().get(), false, info);
301     }
302 #endif
303 
304     return Drawing::Surface::MakeRasterDirect(info, address, pixelmap->GetRowBytes());
305 }
306 
307 #ifdef RS_ENABLE_UNI_RENDER
CreateSurfaceSyncCopyTask(std::shared_ptr<Drawing::Surface> surface,std::unique_ptr<Media::PixelMap> & pixelMap,NodeId id,const RSSurfaceCaptureConfig & captureConfig,int32_t rotation)308 std::function<void()> RSUiCaptureSoloTaskParallel::CreateSurfaceSyncCopyTask(
309     std::shared_ptr<Drawing::Surface> surface, std::unique_ptr<Media::PixelMap>& pixelMap,
310     NodeId id, const RSSurfaceCaptureConfig& captureConfig, int32_t rotation)
311 {
312     Drawing::BackendTexture backendTexture = surface->GetBackendTexture();
313     if (!backendTexture.IsValid()) {
314         RS_LOGE("RSUiCaptureSoloTaskParallel: SkiaSurface bind Image failed: BackendTexture is invalid");
315         return {};
316     }
317     auto wrapper = std::make_shared<std::tuple<std::unique_ptr<Media::PixelMap>>>();
318     std::get<0>(*wrapper) = std::move(pixelMap);
319     auto wrapperSf = std::make_shared<std::tuple<std::shared_ptr<Drawing::Surface>>>();
320     std::get<0>(*wrapperSf) = std::move(surface);
321     std::function<void()> copytask = [
322         &pixelMap, wrapper, captureConfig, backendTexture, wrapperSf, id, rotation]() -> void {
323         RS_TRACE_NAME_FMT("TakeSurfaceCaptureSolo: copy and send capture");
324         if (!backendTexture.IsValid()) {
325             RS_LOGE("RSUiCaptureSoloTaskParallel: Surface bind Image failed: BackendTexture is invalid");
326             std::get<0>(*wrapper) = nullptr;
327             RSUniRenderUtil::ClearNodeCacheSurface(
328                 std::move(std::get<0>(*wrapperSf)), nullptr, UNI_MAIN_THREAD_INDEX, 0);
329             return;
330         }
331         auto pixelmap = std::move(std::get<0>(*wrapper));
332         if (pixelmap == nullptr) {
333             RS_LOGE("RSUiCaptureSoloTaskParallel: pixelmap == nullptr");
334             std::get<0>(*wrapper) = nullptr;
335             RSUniRenderUtil::ClearNodeCacheSurface(
336                 std::move(std::get<0>(*wrapperSf)), nullptr, UNI_MAIN_THREAD_INDEX, 0);
337             return;
338         }
339 
340         Drawing::ImageInfo info = Drawing::ImageInfo{ pixelmap->GetWidth(), pixelmap->GetHeight(),
341             Drawing::COLORTYPE_RGBA_8888, Drawing::ALPHATYPE_PREMUL };
342         Drawing::TextureOrigin textureOrigin = Drawing::TextureOrigin::BOTTOM_LEFT;
343         Drawing::BitmapFormat bitmapFormat =
344             Drawing::BitmapFormat{ Drawing::COLORTYPE_RGBA_8888, Drawing::ALPHATYPE_PREMUL };
345         std::shared_ptr<Drawing::Surface> surface;
346         auto grContext = RSBackgroundThread::Instance().GetShareGPUContext();
347         if (!grContext) {
348             RS_LOGE("RSUiCaptureSoloTaskParallel: SharedGPUContext get failed");
349             std::get<0>(*wrapper) = nullptr;
350             return;
351         }
352 
353         auto tmpImg = std::make_shared<Drawing::Image>();
354         tmpImg->BuildFromTexture(*grContext, backendTexture.GetTextureInfo(),
355             textureOrigin, bitmapFormat, nullptr);
356         if (!CopyDataToPixelMap(tmpImg, pixelmap)) {
357             RS_LOGE("RSUiCaptureSoloTaskParallel: CopyDataToPixelMap failed");
358             std::get<0>(*wrapper) = nullptr;
359             RSUniRenderUtil::ClearNodeCacheSurface(
360                 std::move(std::get<0>(*wrapperSf)), nullptr, UNI_MAIN_THREAD_INDEX, 0);
361             return;
362         }
363 
364         if (rotation) {
365             pixelmap->rotate(rotation);
366         }
367         // To get dump image
368         // execute "param set rosen.dumpsurfacetype.enabled 3 && setenforce 0"
369         RSBaseRenderUtil::WritePixelMapToPng(*pixelmap);
370         RS_LOGI("RSUiCaptureSoloTaskParallel::CaptureSoloNodePixelMap CaptureSolo success nodeId:[%{public}" PRIu64
371             "], pixelMap width: %{public}d, height: %{public}d", id, pixelmap->GetWidth(), pixelmap->GetHeight());
372         pixelMap = std::move(pixelmap);
373         RSBackgroundThread::Instance().CleanGrResource();
374         RSUniRenderUtil::ClearNodeCacheSurface(
375             std::move(std::get<0>(*wrapperSf)), nullptr, UNI_MAIN_THREAD_INDEX, 0);
376     };
377     return copytask;
378 }
379 #endif
380 } // namespace Rosen
381 } // namespace OHOS
382