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