• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2024 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_task_parallel.h"
17 
18 #include <memory>
19 #include <sys/mman.h>
20 
21 #include "draw/surface.h"
22 #include "draw/color.h"
23 #include "rs_trace.h"
24 
25 #include "common/rs_background_thread.h"
26 #include "common/rs_obj_abs_geometry.h"
27 #include "feature/capture/rs_surface_capture_task_parallel.h"
28 #include "feature/uifirst/rs_uifirst_manager.h"
29 #include "feature_cfg/graphic_feature_param_manager.h"
30 #include "memory/rs_tag_tracker.h"
31 #include "params/rs_surface_render_params.h"
32 #include "pipeline/render_thread/rs_uni_render_util.h"
33 #include "pipeline/rs_base_render_node.h"
34 #include "pipeline/rs_screen_render_node.h"
35 #include "pipeline/main_thread/rs_main_thread.h"
36 #include "pipeline/rs_paint_filter_canvas.h"
37 #include "pipeline/main_thread/rs_render_service_connection.h"
38 #include "pipeline/rs_surface_render_node.h"
39 #include "pipeline/rs_uni_render_judgement.h"
40 #include "platform/common/rs_log.h"
41 #include "platform/drawing/rs_surface.h"
42 #include "render/rs_drawing_filter.h"
43 #include "render/rs_skia_filter.h"
44 #include "screen_manager/rs_screen_manager.h"
45 #include "screen_manager/rs_screen_mode_info.h"
46 #include "drawable/rs_canvas_render_node_drawable.h"
47 #include "pipeline/rs_canvas_render_node.h"
48 
49 #ifdef RS_ENABLE_VK
50 #include "platform/ohos/backend/native_buffer_utils.h"
51 #endif
52 
53 #ifdef RS_PROFILER_ENABLED
54 #include "rs_profiler_capture_recorder.h"
55 #endif
56 
57 namespace OHOS {
58 namespace Rosen {
59 constexpr uint32_t ALPHA_MASK = 0xFF000000;
60 namespace {
61     const std::string UICAPTURE_TASK_PREFIX = "uicapture_task_";
62 };
63 
64 #ifdef RS_ENABLE_GPU
DrawCapturedImg(Drawing::Image & image,Drawing::Surface & surface,const Drawing::BackendTexture & backendTexture,Drawing::TextureOrigin & textureOrigin,Drawing::BitmapFormat & bitmapFormat)65 static inline void DrawCapturedImg(Drawing::Image& image,
66     Drawing::Surface& surface, const Drawing::BackendTexture& backendTexture,
67     Drawing::TextureOrigin& textureOrigin, Drawing::BitmapFormat& bitmapFormat)
68 {
69     RSPaintFilterCanvas canvas(&surface);
70     auto gpuContext = canvas.GetGPUContext();
71     if (gpuContext == nullptr) {
72         RS_LOGE("DrawCapturedImg failed: gpuContext is nullptr");
73         return;
74     }
75     image.BuildFromTexture(*gpuContext, backendTexture.GetTextureInfo(),
76         textureOrigin, bitmapFormat, nullptr);
77     canvas.DrawImage(image, 0.f, 0.f, Drawing::SamplingOptions());
78     surface.FlushAndSubmit(true);
79 }
80 #endif
81 
PixelMapSamplingDump(std::unique_ptr<Media::PixelMap> & pixelmap,int32_t x,int32_t y)82 uint32_t PixelMapSamplingDump(std::unique_ptr<Media::PixelMap>& pixelmap, int32_t x, int32_t y)
83 {
84     if (pixelmap == nullptr) {
85         RS_LOGE("RSUiCaptureTaskParallel::PixelMapSamplingDump fail: pixelmap is nullptr");
86         return 0;
87     }
88     if (x < 0 || y < 0 || x >= pixelmap->GetWidth() || y >= pixelmap->GetHeight()) {
89         RS_LOGE("RSUiCaptureTaskParallel::PixelMapSamplingDump fail: x or y invalid");
90         return 0;
91     }
92     uint32_t pixel = 0;
93     pixelmap->ReadPixel({x, y}, pixel);
94     return pixel;
95 }
96 
IsRectValid(NodeId nodeId,const Drawing::Rect & specifiedAreaRect)97 bool RSUiCaptureTaskParallel::IsRectValid(NodeId nodeId, const Drawing::Rect& specifiedAreaRect)
98 {
99     RS_LOGD("RSUiCaptureTaskParallel::IsRectValid: NodeId:[%{public}" PRIu64 "],"
100         " Rect Left is [%{public}f], Top is [%{public}f],"
101         " Right is [%{public}f], Bottom is [%{public}f],",
102         nodeId, specifiedAreaRect.GetLeft(), specifiedAreaRect.GetTop(),
103         specifiedAreaRect.GetRight(), specifiedAreaRect.GetBottom());
104     auto node = RSMainThread::Instance()->GetContext().GetNodeMap().GetRenderNode(nodeId);
105     if (node == nullptr) {
106         RS_LOGE("RSUiCaptureTaskParallel::IsRectValid: Invalid nodeId:[%{public}" PRIu64 "]", nodeId);
107         return false;
108     }
109     if (!specifiedAreaRect.IsValid()) {
110         RS_LOGD("RSUiCaptureTaskParallel::IsRectValid: specifiedAreaRect is an invalid rect");
111         return false;
112     }
113     if ((specifiedAreaRect.GetWidth() > node->GetRenderProperties().GetBoundsWidth()) ||
114         (specifiedAreaRect.GetHeight() > node->GetRenderProperties().GetBoundsHeight()) ||
115         (specifiedAreaRect.GetLeft() < 0) || (specifiedAreaRect.GetTop() < 0) ||
116         (specifiedAreaRect.GetRight() > node->GetRenderProperties().GetBoundsWidth()) ||
117         (specifiedAreaRect.GetBottom() > node->GetRenderProperties().GetBoundsHeight())) {
118         RS_LOGE("RSUiCaptureTaskParallel::IsRectValid: specifiedAreaRect is out of bounds");
119         return false;
120     }
121     return true;
122 }
123 
Capture(NodeId id,sptr<RSISurfaceCaptureCallback> callback,const RSSurfaceCaptureConfig & captureConfig,const Drawing::Rect & specifiedAreaRect)124 void RSUiCaptureTaskParallel::Capture(NodeId id, sptr<RSISurfaceCaptureCallback> callback,
125     const RSSurfaceCaptureConfig& captureConfig, const Drawing::Rect& specifiedAreaRect)
126 {
127     if (callback == nullptr) {
128         RS_LOGE("RSUiCaptureTaskParallel::Capture nodeId:[%{public}" PRIu64 "], callback is nullptr", id);
129         return;
130     }
131 
132     RS_LOGI("RSUiCaptureTaskParallel::Capture nodeId:[%{public}" PRIu64 "]", id);
133     captureCount_++;
134     std::shared_ptr<RSUiCaptureTaskParallel> captureHandle =
135         std::make_shared<RSUiCaptureTaskParallel>(id, captureConfig);
136     if (captureHandle == nullptr) {
137         RS_LOGE("RSUiCaptureTaskParallel::Capture captureHandle is nullptr!");
138         ProcessUiCaptureCallback(callback, id, captureConfig, nullptr);
139         return;
140     }
141     if (!captureConfig.uiCaptureInRangeParam.useBeginNodeSize && !captureHandle->UpdateStartAndEndNodeRect()) {
142         RS_LOGE("RSUiCaptureTaskParallel::Capture UpdateStartAndEndNodeRect error!");
143         ProcessUiCaptureCallback(callback, id, captureConfig, nullptr);
144         return;
145     }
146     if (!captureHandle->CreateResources(specifiedAreaRect)) {
147         RS_LOGE("RSUiCaptureTaskParallel::Capture CreateResources failed");
148         ProcessUiCaptureCallback(callback, id, captureConfig, nullptr);
149         return;
150     }
151     Drawing::Rect chosenRect;
152     Drawing::Rect invalidRect(0.f, 0.f, 0.f, 0.f);
153     if (!IsRectValid(id, specifiedAreaRect)) {
154         chosenRect = invalidRect;
155         RS_LOGD("RSUiCaptureTaskParallel::Capture invalid rect");
156     } else {
157         chosenRect = specifiedAreaRect;
158     }
159     captureHandle->IsStartEndSameNode();
160     auto taskName = UICAPTURE_TASK_PREFIX + std::to_string(id);
161     std::function<void()> captureTask = [captureHandle, id, captureConfig, callback, chosenRect]() -> void {
162         RSSystemProperties::SetForceHpsBlurDisabled(true);
163         if (!captureHandle->Run(callback, chosenRect)) {
164             ProcessUiCaptureCallback(callback, id, captureConfig, nullptr);
165         }
166         RSSystemProperties::SetForceHpsBlurDisabled(false);
167     };
168     // Make the priority of uicapture task is lower than render task
169     RSUniRenderThread::Instance().PostTask(captureTask, taskName, 0, AppExecFwk::EventQueue::Priority::HIGH);
170 }
171 
CreateResources(const Drawing::Rect & specifiedAreaRect)172 bool RSUiCaptureTaskParallel::CreateResources(const Drawing::Rect& specifiedAreaRect)
173 {
174     if (ROSEN_EQ(captureConfig_.scaleX, 0.f) || ROSEN_EQ(captureConfig_.scaleY, 0.f) ||
175         captureConfig_.scaleX < 0.f || captureConfig_.scaleY < 0.f) {
176         RS_LOGE("RSUiCaptureTaskParallel::CreateResources: SurfaceCapture scale is invalid.");
177         return false;
178     }
179     auto node = RSMainThread::Instance()->GetContext().GetNodeMap().GetRenderNode(nodeId_);
180     if (node == nullptr) {
181         RS_LOGE("RSUiCaptureTaskParallel::CreateResources: Invalid nodeId:[%{public}" PRIu64 "]",
182             nodeId_);
183         return false;
184     }
185 
186     if (node->GetType() != RSRenderNodeType::ROOT_NODE &&
187         node->GetType() != RSRenderNodeType::CANVAS_NODE &&
188         node->GetType() != RSRenderNodeType::CANVAS_DRAWING_NODE &&
189         node->GetType() != RSRenderNodeType::SURFACE_NODE) {
190         RS_LOGE("RSUiCaptureTaskParallel::CreateResources: Invalid RSRenderNodeType!");
191         return false;
192     }
193     Drawing::RectF targetRect = specifiedAreaRect;
194     if (HasEndNodeRect() && !isStartEndNodeSame_) {
195         auto endNode = RSMainThread::Instance()->GetContext().GetNodeMap().GetRenderNode(endNodeId_);
196         if (endNode == nullptr) {
197             RS_LOGE("RSUiCaptureTaskParallel::CreateResources: Invalid endNodeId:[%{public}" PRIu64 "]", endNodeId_);
198             return false;
199         }
200         if (auto surfaceNode = endNode->ReinterpretCastTo<RSSurfaceRenderNode>()) {
201             endNodeDrawable_ = std::static_pointer_cast<DrawableV2::RSRenderNodeDrawable>(
202                 DrawableV2::RSRenderNodeDrawableAdapter::OnGenerate(surfaceNode));
203         } else if (auto canvasNode = endNode->ReinterpretCastTo<RSCanvasRenderNode>()) {
204             endNodeDrawable_ = std::static_pointer_cast<DrawableV2::RSRenderNodeDrawable>(
205                 DrawableV2::RSRenderNodeDrawableAdapter::OnGenerate(canvasNode));
206         } else {
207             RS_LOGE("RSUiCaptureTaskParallel::CreateResources: Invalid RSRenderEndNode");
208             return false;
209         }
210         const auto& endNodeParams = endNodeDrawable_->GetRenderParams();
211         targetRect = endNodeParams->GetBounds();
212     }
213 #ifdef RS_ENABLE_VK
214     float nodeBoundsWidth = node->GetRenderProperties().GetBoundsWidth();
215     float nodeBoundsHeight = node->GetRenderProperties().GetBoundsHeight();
216     int32_t width = ceil(nodeBoundsWidth * captureConfig_.scaleX);
217     int32_t height = ceil(nodeBoundsHeight * captureConfig_.scaleY);
218     if (width > 0 && static_cast<int32_t>(OHOS::Rosen::NativeBufferUtils::VKIMAGE_LIMIT_SIZE) / width < height) {
219         RS_LOGE("RSUiCaptureTaskParallel::CreateResources: image is too large, width:%{public}d, height::%{public}d",
220             width, height);
221         return false;
222     }
223     RS_LOGD("RSUiCaptureTaskParallel::CreateResources: Origin nodeBoundsWidth is [%{public}f,]"
224         " Origin nodeBoundsHeight is [%{public}f]", nodeBoundsWidth, nodeBoundsHeight);
225 #endif
226     if (auto surfaceNode = node->ReinterpretCastTo<RSSurfaceRenderNode>()) {
227         // Determine whether cache can be used
228         auto curNode = surfaceNode;
229         auto parentNode = RSBaseRenderNode::ReinterpretCast<RSSurfaceRenderNode>(surfaceNode->GetParent().lock());
230         if (parentNode && parentNode->IsLeashWindow() && parentNode->ShouldPaint() &&
231             (parentNode->GetLastFrameUifirstFlag() == MultiThreadCacheType::LEASH_WINDOW ||
232             parentNode->GetLastFrameUifirstFlag() == MultiThreadCacheType::NONFOCUS_WINDOW)) {
233             curNode = parentNode;
234         }
235 
236         nodeDrawable_ = std::static_pointer_cast<DrawableV2::RSRenderNodeDrawable>(
237             DrawableV2::RSRenderNodeDrawableAdapter::OnGenerate(curNode));
238         if (IsRectValid(nodeId_, targetRect)) {
239             pixelMap_ = CreatePixelMapByRect(targetRect);
240         } else {
241             pixelMap_ = CreatePixelMapByNode(curNode);
242         }
243     } else if (auto canvasNode = node->ReinterpretCastTo<RSCanvasRenderNode>()) {
244         nodeDrawable_ = std::static_pointer_cast<DrawableV2::RSRenderNodeDrawable>(
245             DrawableV2::RSRenderNodeDrawableAdapter::OnGenerate(canvasNode));
246         if (IsRectValid(nodeId_, targetRect)) {
247             pixelMap_ = CreatePixelMapByRect(targetRect);
248         } else {
249             pixelMap_ = CreatePixelMapByNode(canvasNode);
250         }
251     } else {
252         RS_LOGE("RSUiCaptureTaskParallel::CreateResources: Invalid RSRenderNode!");
253         return false;
254     }
255 
256     if (pixelMap_ == nullptr) {
257         RS_LOGE("RSUiCaptureTaskParallel::CreateResources: pixelMap_ is nullptr!");
258         return false;
259     }
260     return true;
261 }
262 
Run(sptr<RSISurfaceCaptureCallback> callback,const Drawing::Rect & specifiedAreaRect)263 bool RSUiCaptureTaskParallel::Run(sptr<RSISurfaceCaptureCallback> callback, const Drawing::Rect& specifiedAreaRect)
264 {
265     RS_TRACE_NAME_FMT("RSUiCaptureTaskParallel::TakeSurfaceCapture. NodeId: [%" PRIu64 "], from pid: [%d]",
266         nodeId_, ExtractPid(nodeId_));
267 
268 #if defined(RS_ENABLE_GL) || defined(RS_ENABLE_VK)
269     auto renderContext = RSUniRenderThread::Instance().GetRenderEngine()->GetRenderContext();
270     auto grContext = renderContext != nullptr ? renderContext->GetDrGPUContext() : nullptr;
271     std::string nodeName("RSUiCaptureTaskParallel");
272     RSTagTracker tagTracker(renderContext != nullptr ? renderContext->GetSharedDrGPUContext() : nullptr,
273         nodeId_, RSTagTracker::TAGTYPE::TAG_CAPTURE, nodeName);
274 #endif
275     auto surface = CreateSurface(pixelMap_);
276     if (surface == nullptr) {
277         RS_LOGE("RSUiCaptureTaskParallel::Run: surface is nullptr!");
278         return false;
279     }
280     if (!nodeDrawable_) {
281         RS_LOGE("RSUiCaptureTaskParallel::Run: Invalid RSRenderNodeDrawable!");
282         return false;
283     }
284 
285     RSPaintFilterCanvas canvas(surface.get());
286     canvas.Scale(captureConfig_.scaleX, captureConfig_.scaleY);
287     canvas.SetDisableFilterCache(true);
288     canvas.SetUICapture(true);
289     const auto& nodeParams = nodeDrawable_->GetRenderParams();
290     if (UNLIKELY(!nodeParams)) {
291         RS_LOGE("RSUiCaptureTaskParallel::Run: RenderParams is nullptr!");
292         return false;
293     }
294 #ifdef RS_PROFILER_ENABLED
295     // check if capturing was triggered, if so - add the recording canvas
296     if (auto canvasRec = RSCaptureRecorder::GetInstance().TryComponentScreenshotCapture(
297         static_cast<float>(canvas.GetWidth()), static_cast<float>(canvas.GetHeight()))) {
298         canvas.AddCanvas(canvasRec);
299     }
300 #endif
301     Drawing::Matrix relativeMatrix = Drawing::Matrix();
302     relativeMatrix.Set(Drawing::Matrix::Index::SCALE_X, captureConfig_.scaleX);
303     relativeMatrix.Set(Drawing::Matrix::Index::SCALE_Y, captureConfig_.scaleY);
304     int32_t rectLeft = specifiedAreaRect.GetLeft();
305     int32_t rectTop = specifiedAreaRect.GetTop();
306     Drawing::scalar xOffset = static_cast<Drawing::scalar>(-1 * rectLeft);
307     Drawing::scalar yOffset = static_cast<Drawing::scalar>(-1 * rectTop);
308     relativeMatrix.Set(Drawing::Matrix::Index::TRANS_X, xOffset);
309     relativeMatrix.Set(Drawing::Matrix::Index::TRANS_Y, yOffset);
310     RS_LOGD("RSUiCaptureTaskParallel::Run: specifiedAreaRect offsetX is [%{public}f], offsetY is [%{public}f]",
311         xOffset, yOffset);
312     Drawing::Matrix invertMatrix;
313     if (HasEndNodeRect()) {
314         if (endMatrix_.Invert(invertMatrix)) {
315             relativeMatrix.PreConcat(invertMatrix);
316         }
317         relativeMatrix.PreConcat(startMatrix_);
318     } else {
319         if (nodeParams->GetMatrix().Invert(invertMatrix)) {
320             relativeMatrix.PreConcat(invertMatrix);
321         }
322     }
323     canvas.SetMatrix(relativeMatrix);
324 
325     RSUiFirstProcessStateCheckerHelper stateCheckerHepler(
326         nodeParams->GetFirstLevelNodeId(), nodeParams->GetUifirstRootNodeId());
327     RSUniRenderThread::SetCaptureParam(CaptureParam(true, true, false, false, false, false, false, false,
328         captureConfig_.uiCaptureInRangeParam.endNodeId));
329     DrawableV2::RSRenderNodeDrawable::ClearSnapshotProcessedNodeCount();
330     if (HasEndNodeRect() && !isStartEndNodeSame_) {
331         auto offScreenWidth = nodeParams->GetBounds().GetWidth();
332         auto offScreenHeight = nodeParams->GetBounds().GetHeight();
333         auto originSurface = canvas.GetSurface();
334         if (originSurface == nullptr) {
335             RS_LOGE("RSUiCaptureTaskParallel::Run: originSurface is nullptr");
336             return false;
337         }
338         auto offScreenSurface = originSurface->MakeSurface(offScreenWidth, offScreenHeight);
339         if (offScreenSurface == nullptr) {
340             RS_LOGE("RSUiCaptureTaskParallel::Run: offScreenSurface is nullptr");
341             return false;
342         }
343         RSPaintFilterCanvas offScreenCanvas(offScreenSurface.get());
344         offScreenCanvas.SetDisableFilterCache(true);
345         offScreenCanvas.SetUICapture(true);
346         offScreenCanvas.CopyHDRConfiguration(canvas);
347         offScreenCanvas.CopyConfigurationToOffscreenCanvas(canvas);
348         offScreenCanvas.ResetMatrix();
349         nodeDrawable_->OnCapture(offScreenCanvas);
350         auto image = offScreenSurface->GetImageSnapshot();
351         if (!image) {
352             RS_LOGE("RSUiCaptureTaskParallel::Run: image is nullptr");
353             return false;
354         }
355         RS_LOGD("RSUiCaptureTaskParallel::Run: offScreenSurface width: %{public}d, height: %{public}d",
356             offScreenSurface->Width(), offScreenSurface->Height());
357         canvas.DrawImage(*image, 0, 0, Drawing::SamplingOptions());
358     } else {
359         nodeDrawable_->OnCapture(canvas);
360     }
361     RS_LOGI("RSUiCaptureTaskParallel::Run: NodeId: [%{public}" PRIu64 "], "
362         "the number of total processedNodes: [%{public}d]",
363         nodeId_, DrawableV2::RSRenderNodeDrawable::GetSnapshotProcessedNodeCount());
364     DrawableV2::RSRenderNodeDrawable::ClearSnapshotProcessedNodeCount();
365     RSUniRenderThread::ResetCaptureParam();
366 #ifdef RS_PROFILER_ENABLED
367     // finish capturing if started
368     RSCaptureRecorder::GetInstance().EndComponentScreenshotCapture();
369 #endif
370 #if (defined (RS_ENABLE_GL) || defined (RS_ENABLE_VK)) && (defined RS_ENABLE_EGLIMAGE)
371 #ifdef RS_ENABLE_UNI_RENDER
372     bool snapshotDmaEnabled = system::GetBoolParameter("rosen.snapshotDma.enabled", true);
373     bool isEnableFeature = GetFeatureParamValue("CaptureConfig",
374         &CaptureBaseParam::IsSnapshotWithDMAEnabled).value_or(false);
375     if (snapshotDmaEnabled && isEnableFeature) {
376         RSUniRenderUtil::OptimizedFlushAndSubmit(surface, grContext, GetFeatureParamValue("UICaptureConfig",
377             &UICaptureParam::IsUseOptimizedFlushAndSubmitEnabled).value_or(false));
378         auto copytask =
379             RSUiCaptureTaskParallel::CreateSurfaceSyncCopyTask(
380                 surface, std::move(pixelMap_), nodeId_, captureConfig_, callback);
381         if (!copytask) {
382             RS_LOGE("RSUiCaptureTaskParallel::Run: create capture task failed!");
383             return false;
384         }
385         RSBackgroundThread::Instance().PostTask(copytask);
386         return true;
387     } else {
388         std::shared_ptr<Drawing::Image> img(surface.get()->GetImageSnapshot());
389         if (!img) {
390             RS_LOGE("RSUiCaptureTaskParallel::Run: img is nullptr");
391             return false;
392         }
393         if (!CopyDataToPixelMap(img, pixelMap_)) {
394             RS_LOGE("RSUiCaptureTaskParallel::Run: CopyDataToPixelMap failed");
395             return false;
396         }
397     }
398 #endif
399 #endif
400     // To get dump image
401     // execute "param set rosen.dumpsurfacetype.enabled 3 && setenforce 0"
402     RSBaseRenderUtil::WritePixelMapToPng(*pixelMap_);
403     RS_LOGI("RSUiCaptureTaskParallel::Capture DMADisable capture success nodeId:[%{public}" PRIu64
404             "], pixelMap width: %{public}d, height: %{public}d",
405         nodeId_, pixelMap_->GetWidth(), pixelMap_->GetHeight());
406     ProcessUiCaptureCallback(callback, nodeId_, captureConfig_, pixelMap_.get());
407     return true;
408 }
409 
CreatePixelMapByRect(const Drawing::Rect & specifiedAreaRect) const410 std::unique_ptr<Media::PixelMap> RSUiCaptureTaskParallel::CreatePixelMapByRect(
411     const Drawing::Rect& specifiedAreaRect) const
412 {
413     float pixmapWidth = specifiedAreaRect.GetWidth();
414     float pixmapHeight = specifiedAreaRect.GetHeight();
415     Media::InitializationOptions opts;
416     opts.size.width = ceil(pixmapWidth * captureConfig_.scaleX);
417     opts.size.height = ceil(pixmapHeight * captureConfig_.scaleY);
418     RS_LOGD("RSUiCaptureTaskParallel::CreatePixelMapByRect:"
419         " origin pixelmap width is [%{public}f], height is [%{public}f],"
420         " created pixelmap width is [%{public}u], height is [%{public}u],"
421         " the scale is scaleX:[%{public}f], scaleY:[%{public}f]",
422         pixmapWidth, pixmapHeight, opts.size.width, opts.size.height,
423         captureConfig_.scaleX, captureConfig_.scaleY);
424     return Media::PixelMap::Create(opts);
425 }
426 
CreatePixelMapByNode(std::shared_ptr<RSRenderNode> node) const427 std::unique_ptr<Media::PixelMap> RSUiCaptureTaskParallel::CreatePixelMapByNode(
428     std::shared_ptr<RSRenderNode> node) const
429 {
430     float pixmapWidth = node->GetRenderProperties().GetBoundsWidth();
431     float pixmapHeight = node->GetRenderProperties().GetBoundsHeight();
432     Media::InitializationOptions opts;
433     opts.size.width = ceil(pixmapWidth * captureConfig_.scaleX);
434     opts.size.height = ceil(pixmapHeight * captureConfig_.scaleY);
435     RS_LOGD("RSUiCaptureTaskParallel::CreatePixelMapByNode: NodeId:[%{public}" PRIu64 "],"
436         " origin pixelmap width is [%{public}f], height is [%{public}f],"
437         " created pixelmap width is [%{public}u], height is [%{public}u],"
438         " the scale is scaleX:[%{public}f], scaleY:[%{public}f]",
439         node->GetId(), pixmapWidth, pixmapHeight, opts.size.width, opts.size.height,
440         captureConfig_.scaleX, captureConfig_.scaleY);
441     return Media::PixelMap::Create(opts);
442 }
443 
CreateSurface(const std::unique_ptr<Media::PixelMap> & pixelmap) const444 std::shared_ptr<Drawing::Surface> RSUiCaptureTaskParallel::CreateSurface(
445     const std::unique_ptr<Media::PixelMap>& pixelmap) const
446 {
447     if (pixelmap == nullptr) {
448         RS_LOGE("RSUiCaptureTaskParallel::CreateSurface: pixelmap == nullptr");
449         return nullptr;
450     }
451     auto address = const_cast<uint32_t*>(pixelmap->GetPixel32(0, 0));
452     if (address == nullptr) {
453         RS_LOGE("RSUiCaptureTaskParallel::CreateSurface: address == nullptr");
454         return nullptr;
455     }
456     Drawing::ImageInfo info = Drawing::ImageInfo{pixelmap->GetWidth(), pixelmap->GetHeight(),
457         Drawing::ColorType::COLORTYPE_RGBA_8888, Drawing::AlphaType::ALPHATYPE_PREMUL};
458 
459 #if (defined RS_ENABLE_GL) && (defined RS_ENABLE_EGLIMAGE)
460     if (RSSystemProperties::GetGpuApiType() == GpuApiType::OPENGL) {
461         auto renderContext = RSUniRenderThread::Instance().GetRenderEngine()->GetRenderContext();
462         if (renderContext == nullptr) {
463             RS_LOGE("RSUiCaptureTaskParallel::CreateSurface: renderContext is nullptr");
464             return nullptr;
465         }
466         renderContext->SetUpGpuContext(nullptr);
467         return Drawing::Surface::MakeRenderTarget(renderContext->GetDrGPUContext(), false, info);
468     }
469 #endif
470 #ifdef RS_ENABLE_VK
471     if (RSSystemProperties::GetGpuApiType() == GpuApiType::VULKAN ||
472         RSSystemProperties::GetGpuApiType() == GpuApiType::DDGR) {
473         return Drawing::Surface::MakeRenderTarget(
474             RSUniRenderThread::Instance().GetRenderEngine()->GetSkContext().get(), false, info);
475     }
476 #endif
477 
478     return Drawing::Surface::MakeRasterDirect(info, address, pixelmap->GetRowBytes());
479 }
480 
481 #ifdef RS_ENABLE_UNI_RENDER
CreateSurfaceSyncCopyTask(std::shared_ptr<Drawing::Surface> surface,std::unique_ptr<Media::PixelMap> pixelMap,NodeId id,const RSSurfaceCaptureConfig & captureConfig,sptr<RSISurfaceCaptureCallback> callback,int32_t rotation)482 std::function<void()> RSUiCaptureTaskParallel::CreateSurfaceSyncCopyTask(
483     std::shared_ptr<Drawing::Surface> surface, std::unique_ptr<Media::PixelMap> pixelMap,
484     NodeId id, const RSSurfaceCaptureConfig& captureConfig, sptr<RSISurfaceCaptureCallback> callback,
485     int32_t rotation)
486 {
487     Drawing::BackendTexture backendTexture = surface->GetBackendTexture();
488     if (!backendTexture.IsValid()) {
489         RS_LOGE("RSUiCaptureTaskParallel: SkiaSurface bind Image failed: BackendTexture is invalid");
490         return {};
491     }
492     auto wrapper = std::make_shared<std::tuple<std::unique_ptr<Media::PixelMap>>>();
493     std::get<0>(*wrapper) = std::move(pixelMap);
494     auto wrapperSf = std::make_shared<std::tuple<std::shared_ptr<Drawing::Surface>>>();
495     std::get<0>(*wrapperSf) = std::move(surface);
496     std::function<void()> copytask = [
497         wrapper, captureConfig, callback, backendTexture, wrapperSf, id, rotation]() -> void {
498         RS_TRACE_NAME_FMT("copy and send capture useDma:%d", captureConfig.useDma);
499         if (!backendTexture.IsValid()) {
500             RS_LOGE("RSUiCaptureTaskParallel: Surface bind Image failed: BackendTexture is invalid");
501             ProcessUiCaptureCallback(callback, id, captureConfig, nullptr);
502             RSUniRenderUtil::ClearNodeCacheSurface(
503                 std::move(std::get<0>(*wrapperSf)), nullptr, UNI_MAIN_THREAD_INDEX, 0);
504             return;
505         }
506         auto pixelmap = std::move(std::get<0>(*wrapper));
507         if (pixelmap == nullptr) {
508             RS_LOGE("RSUiCaptureTaskParallel: pixelmap == nullptr");
509             ProcessUiCaptureCallback(callback, id, captureConfig, nullptr);
510             RSUniRenderUtil::ClearNodeCacheSurface(
511                 std::move(std::get<0>(*wrapperSf)), nullptr, UNI_MAIN_THREAD_INDEX, 0);
512             return;
513         }
514 
515         Drawing::ImageInfo info = Drawing::ImageInfo{ pixelmap->GetWidth(), pixelmap->GetHeight(),
516             Drawing::COLORTYPE_RGBA_8888, Drawing::ALPHATYPE_PREMUL };
517         Drawing::TextureOrigin textureOrigin = Drawing::TextureOrigin::BOTTOM_LEFT;
518         Drawing::BitmapFormat bitmapFormat =
519             Drawing::BitmapFormat{ Drawing::COLORTYPE_RGBA_8888, Drawing::ALPHATYPE_PREMUL };
520         std::shared_ptr<Drawing::Surface> surface;
521         auto grContext = RSBackgroundThread::Instance().GetShareGPUContext();
522         if (!grContext) {
523             RS_LOGE("RSUiCaptureTaskParallel: SharedGPUContext get failed");
524             ProcessUiCaptureCallback(callback, id, captureConfig, nullptr);
525             return;
526         }
527 #if defined(ROSEN_OHOS) && defined(RS_ENABLE_VK)
528         DmaMem dmaMem;
529         if (captureConfig.useDma && GetFeatureParamValue("UICaptureConfig",
530             &UICaptureParam::IsUseDMAProcessEnabled).value_or(false) &&
531             (RSSystemProperties::GetGpuApiType() == GpuApiType::VULKAN ||
532             RSSystemProperties::GetGpuApiType() == GpuApiType::DDGR)) {
533             sptr<SurfaceBuffer> surfaceBuffer = dmaMem.DmaMemAlloc(info, pixelmap);
534             surface = dmaMem.GetSurfaceFromSurfaceBuffer(surfaceBuffer, grContext);
535             if (surface == nullptr) {
536                 RS_LOGE("RSUiCaptureTaskParallel: GetSurfaceFromSurfaceBuffer fail.");
537                 ProcessUiCaptureCallback(callback, id, captureConfig, nullptr);
538                 RSUniRenderUtil::ClearNodeCacheSurface(
539                     std::move(std::get<0>(*wrapperSf)), nullptr, UNI_MAIN_THREAD_INDEX, 0);
540                 return;
541             }
542             auto tmpImg = std::make_shared<Drawing::Image>();
543             DrawCapturedImg(*tmpImg, *surface, backendTexture, textureOrigin, bitmapFormat);
544             RS_LOGI("RSUiCaptureTaskParallel::Capture DMA success nodeId:[%{public}" PRIu64
545                 "], pixelMap width: %{public}d, height: %{public}d",
546                 id, pixelmap->GetWidth(), pixelmap->GetHeight());
547         } else {
548 #else
549         {
550 #endif
551             auto tmpImg = std::make_shared<Drawing::Image>();
552             tmpImg->BuildFromTexture(*grContext, backendTexture.GetTextureInfo(),
553                 textureOrigin, bitmapFormat, nullptr);
554             if (!CopyDataToPixelMap(tmpImg, pixelmap)) {
555                 RS_LOGE("RSUiCaptureTaskParallel: CopyDataToPixelMap failed");
556                 ProcessUiCaptureCallback(callback, id, captureConfig, nullptr);
557                 RSUniRenderUtil::ClearNodeCacheSurface(
558                     std::move(std::get<0>(*wrapperSf)), nullptr, UNI_MAIN_THREAD_INDEX, 0);
559                 return;
560             }
561         }
562         if (rotation) {
563             pixelmap->rotate(rotation);
564         }
565         // To get dump image
566         // execute "param set rosen.dumpsurfacetype.enabled 3 && setenforce 0"
567         RSBaseRenderUtil::WritePixelMapToPng(*pixelmap);
568         auto pixelDump = PixelMapSamplingDump(pixelmap, pixelmap->GetWidth() / 2, 0) |
569                          PixelMapSamplingDump(pixelmap, 0, pixelmap->GetHeight() / 2) |
570                          PixelMapSamplingDump(pixelmap, pixelmap->GetWidth() / 2, pixelmap->GetHeight() / 2) |
571                          PixelMapSamplingDump(pixelmap, pixelmap->GetWidth() - 1, pixelmap->GetHeight() / 2) |
572                          PixelMapSamplingDump(pixelmap, pixelmap->GetWidth() / 2, pixelmap->GetHeight() - 1);
573         if ((pixelDump & ALPHA_MASK) == 0) {
574             RS_LOGW("RSUiCaptureTaskParallel::CreateSurfaceSyncCopyTask pixelmap is transparent");
575         }
576         RS_LOGI("RSUiCaptureTaskParallel::Capture capture success nodeId:[%{public}" PRIu64
577                 "], pixelMap width: %{public}d, height: %{public}d",
578             id, pixelmap->GetWidth(), pixelmap->GetHeight());
579         ProcessUiCaptureCallback(callback, id, captureConfig, pixelmap.get());
580         RSBackgroundThread::Instance().CleanGrResource();
581         RSUniRenderUtil::ClearNodeCacheSurface(
582             std::move(std::get<0>(*wrapperSf)), nullptr, UNI_MAIN_THREAD_INDEX, 0);
583     };
584     return copytask;
585 }
586 #endif
587 
588 void RSUiCaptureTaskParallel::ProcessUiCaptureCallback(sptr<RSISurfaceCaptureCallback> callback, NodeId id,
589     const RSSurfaceCaptureConfig& captureConfig, Media::PixelMap* pixelmap)
590 {
591     callback->OnSurfaceCapture(id, captureConfig, pixelmap);
592     RSUiCaptureTaskParallel::captureCount_--;
593     RSMainThread::Instance()->RequestNextVSync();
594 }
595 
596 bool RSUiCaptureTaskParallel::HasEndNodeRect() const
597 {
598     return captureConfig_.uiCaptureInRangeParam.endNodeId != INVALID_NODEID &&
599         !captureConfig_.uiCaptureInRangeParam.useBeginNodeSize;
600 }
601 
602 bool RSUiCaptureTaskParallel::UpdateStartAndEndNodeRect()
603 {
604     auto startNode = RSMainThread::Instance()->GetContext().GetNodeMap().GetRenderNode(nodeId_);
605     if (!startNode) {
606         RS_LOGE("RSUiCaptureTaskParallel::UpdateStartAndEndNodeRect start node nullptr %{public}" PRIu64, nodeId_);
607         return false;
608     }
609     startRect_ = startNode->GetRenderProperties().GetBoundsGeometry()->GetAbsRect();
610     RS_LOGI("RSUiCaptureTaskParallel::UpdateStartAndEndNodeRect startRect %{public}s", startRect_.ToString().c_str());
611 
612     NodeId endNodeId = captureConfig_.uiCaptureInRangeParam.endNodeId;
613     endNodeId_ = endNodeId;
614     if (!HasEndNodeRect()) {
615         RS_LOGE("RSUiCaptureTaskParallel::UpdateStartAndEndNodeRect end node invalid %{public}" PRIu64, endNodeId);
616         return false;
617     }
618 
619     auto endNode = RSMainThread::Instance()->GetContext().GetNodeMap().GetRenderNode(endNodeId);
620     if (!endNode) {
621         RS_LOGE("RSUiCaptureTaskParallel::UpdateStartAndEndNodeRect end node nullptr %{public}" PRIu64, endNodeId);
622         return false;
623     }
624     std::vector<NodeId> nodeIdVec;
625     startNode->CollectAllChildren(startNode, nodeIdVec);
626     if (std::find(nodeIdVec.begin(), nodeIdVec.end(), endNodeId) == nodeIdVec.end()) {
627         RS_LOGE("RSUiCaptureTaskParallel::UpdateStartAndEndNodeRect endNode not on tree %{public}" PRIu64, endNodeId);
628         return false;
629     }
630 
631     endRect_ = endNode->GetRenderProperties().GetBoundsGeometry()->GetAbsRect();
632     RS_LOGI("RSUiCaptureTaskParallel::UpdateStartAndEndNodeRect endRect %{public}s", endRect_.ToString().c_str());
633     startMatrix_ = startNode->GetRenderProperties().GetBoundsGeometry()->GetAbsMatrix();
634     endMatrix_ = endNode->GetRenderProperties().GetBoundsGeometry()->GetAbsMatrix();
635 
636     return true;
637 }
638 
639 bool RSUiCaptureTaskParallel::IsStartEndSameNode()
640 {
641     isStartEndNodeSame_ = (nodeId_ == captureConfig_.uiCaptureInRangeParam.endNodeId);
642     RS_LOGD("RSUiCaptureTaskParallel::IsStartEndSameNode isStartEndNodeSame_: %{public}d", isStartEndNodeSame_);
643     return isStartEndNodeSame_;
644 }
645 } // namespace Rosen
646 } // namespace OHOS
647