• 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_display_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 namespace OHOS {
54 namespace Rosen {
55 
56 namespace {
57     const std::string UICAPTURE_TASK_PREFIX = "uicapture_task_";
58 };
59 
60 #ifdef RS_ENABLE_GPU
DrawCapturedImg(Drawing::Image & image,Drawing::Surface & surface,const Drawing::BackendTexture & backendTexture,Drawing::TextureOrigin & textureOrigin,Drawing::BitmapFormat & bitmapFormat)61 static inline void DrawCapturedImg(Drawing::Image& image,
62     Drawing::Surface& surface, const Drawing::BackendTexture& backendTexture,
63     Drawing::TextureOrigin& textureOrigin, Drawing::BitmapFormat& bitmapFormat)
64 {
65     RSPaintFilterCanvas canvas(&surface);
66     auto gpuContext = canvas.GetGPUContext();
67     if (gpuContext == nullptr) {
68         RS_LOGE("DrawCapturedImg failed: gpuContext is nullptr");
69         return;
70     }
71     image.BuildFromTexture(*gpuContext, backendTexture.GetTextureInfo(),
72         textureOrigin, bitmapFormat, nullptr);
73     canvas.DrawImage(image, 0.f, 0.f, Drawing::SamplingOptions());
74     surface.FlushAndSubmit(true);
75 }
76 #endif
77 
IsRectValid(NodeId nodeId,const Drawing::Rect & specifiedAreaRect)78 bool RSUiCaptureTaskParallel::IsRectValid(NodeId nodeId, const Drawing::Rect& specifiedAreaRect)
79 {
80     RS_LOGD("RSUiCaptureTaskParallel::IsRectValid: NodeId:[%{public}" PRIu64 "],"
81         " Rect Left is [%{public}f], Top is [%{public}f],"
82         " Right is [%{public}f], Bottom is [%{public}f],",
83         nodeId, specifiedAreaRect.GetLeft(), specifiedAreaRect.GetTop(),
84         specifiedAreaRect.GetRight(), specifiedAreaRect.GetBottom());
85     auto node = RSMainThread::Instance()->GetContext().GetNodeMap().GetRenderNode(nodeId);
86     if (node == nullptr) {
87         RS_LOGE("RSUiCaptureTaskParallel::IsRectValid: Invalid nodeId:[%{public}" PRIu64 "]", nodeId);
88         return false;
89     }
90     if (!specifiedAreaRect.IsValid()) {
91         RS_LOGD("RSUiCaptureTaskParallel::IsRectValid: specifiedAreaRect is an invalid rect");
92         return false;
93     }
94     if ((specifiedAreaRect.GetWidth() > node->GetRenderProperties().GetBoundsWidth()) ||
95         (specifiedAreaRect.GetHeight() > node->GetRenderProperties().GetBoundsHeight()) ||
96         (specifiedAreaRect.GetLeft() < 0) || (specifiedAreaRect.GetTop() < 0) ||
97         (specifiedAreaRect.GetRight() > node->GetRenderProperties().GetBoundsWidth()) ||
98         (specifiedAreaRect.GetBottom() > node->GetRenderProperties().GetBoundsHeight())) {
99         RS_LOGE("RSUiCaptureTaskParallel::IsRectValid: specifiedAreaRect is out of bounds");
100         return false;
101     }
102     return true;
103 }
104 
Capture(NodeId id,sptr<RSISurfaceCaptureCallback> callback,const RSSurfaceCaptureConfig & captureConfig,const Drawing::Rect & specifiedAreaRect)105 void RSUiCaptureTaskParallel::Capture(NodeId id, sptr<RSISurfaceCaptureCallback> callback,
106     const RSSurfaceCaptureConfig& captureConfig, const Drawing::Rect& specifiedAreaRect)
107 {
108     if (callback == nullptr) {
109         RS_LOGE("RSUiCaptureTaskParallel::Capture nodeId:[%{public}" PRIu64 "], callback is nullptr", id);
110         return;
111     }
112     RS_LOGI("RSUiCaptureTaskParallel::Capture nodeId:[%{public}" PRIu64 "]", id);
113     captureCount_++;
114     std::shared_ptr<RSUiCaptureTaskParallel> captureHandle =
115         std::make_shared<RSUiCaptureTaskParallel>(id, captureConfig);
116     if (captureHandle == nullptr) {
117         RS_LOGE("RSUiCaptureTaskParallel::Capture captureHandle is nullptr!");
118         ProcessUiCaptureCallback(callback, id, captureConfig, nullptr);
119         return;
120     }
121     if (!captureHandle->CreateResources(specifiedAreaRect)) {
122         RS_LOGE("RSUiCaptureTaskParallel::Capture CreateResources failed");
123         ProcessUiCaptureCallback(callback, id, captureConfig, nullptr);
124         return;
125     }
126     Drawing::Rect chosenRect;
127     Drawing::Rect invalidRect(0.f, 0.f, 0.f, 0.f);
128     if (!IsRectValid(id, specifiedAreaRect)) {
129         chosenRect = invalidRect;
130         RS_LOGD("RSUiCaptureTaskParallel::Capture invalid rect");
131     } else {
132         chosenRect = specifiedAreaRect;
133     }
134     auto taskName = UICAPTURE_TASK_PREFIX + std::to_string(id);
135     std::function<void()> captureTask = [captureHandle, id, captureConfig, callback, chosenRect]() -> void {
136         RSSystemProperties::SetForceHpsBlurDisabled(true);
137         if (!captureHandle->Run(callback, chosenRect)) {
138             ProcessUiCaptureCallback(callback, id, captureConfig, nullptr);
139         }
140         RSSystemProperties::SetForceHpsBlurDisabled(false);
141     };
142     // Make the priority of uicapture task is lower than render task
143     RSUniRenderThread::Instance().PostTask(captureTask, taskName, 0, AppExecFwk::EventQueue::Priority::HIGH);
144 }
145 
CreateResources(const Drawing::Rect & specifiedAreaRect)146 bool RSUiCaptureTaskParallel::CreateResources(const Drawing::Rect& specifiedAreaRect)
147 {
148     if (ROSEN_EQ(captureConfig_.scaleX, 0.f) || ROSEN_EQ(captureConfig_.scaleY, 0.f) ||
149         captureConfig_.scaleX < 0.f || captureConfig_.scaleY < 0.f) {
150         RS_LOGE("RSUiCaptureTaskParallel::CreateResources: SurfaceCapture scale is invalid.");
151         return false;
152     }
153     auto node = RSMainThread::Instance()->GetContext().GetNodeMap().GetRenderNode(nodeId_);
154     if (node == nullptr) {
155         RS_LOGE("RSUiCaptureTaskParallel::CreateResources: Invalid nodeId:[%{public}" PRIu64 "]",
156             nodeId_);
157         return false;
158     }
159 
160     if (node->GetType() != RSRenderNodeType::ROOT_NODE &&
161         node->GetType() != RSRenderNodeType::CANVAS_NODE &&
162         node->GetType() != RSRenderNodeType::CANVAS_DRAWING_NODE &&
163         node->GetType() != RSRenderNodeType::SURFACE_NODE) {
164         RS_LOGE("RSUiCaptureTaskParallel::CreateResources: Invalid RSRenderNodeType!");
165         return false;
166     }
167 #ifdef RS_ENABLE_VK
168     float nodeBoundsWidth = node->GetRenderProperties().GetBoundsWidth();
169     float nodeBoundsHeight = node->GetRenderProperties().GetBoundsHeight();
170     int32_t width = ceil(nodeBoundsWidth * captureConfig_.scaleX);
171     int32_t height = ceil(nodeBoundsHeight * captureConfig_.scaleY);
172     if (width > 0 && static_cast<int32_t>(OHOS::Rosen::NativeBufferUtils::VKIMAGE_LIMIT_SIZE) / width < height) {
173         RS_LOGE("RSUiCaptureTaskParallel::CreateResources: image is too large, width:%{public}d, height::%{public}d",
174             width, height);
175         return false;
176     }
177     RS_LOGD("RSUiCaptureTaskParallel::CreateResources: Origin nodeBoundsWidth is [%{public}f,]"
178         " Origin nodeBoundsHeight is [%{public}f]", nodeBoundsWidth, nodeBoundsHeight);
179 #endif
180     if (auto surfaceNode = node->ReinterpretCastTo<RSSurfaceRenderNode>()) {
181         // Determine whether cache can be used
182         auto curNode = surfaceNode;
183         auto parentNode = RSBaseRenderNode::ReinterpretCast<RSSurfaceRenderNode>(surfaceNode->GetParent().lock());
184         if (parentNode && parentNode->IsLeashWindow() && parentNode->ShouldPaint() &&
185             (parentNode->GetLastFrameUifirstFlag() == MultiThreadCacheType::LEASH_WINDOW ||
186             parentNode->GetLastFrameUifirstFlag() == MultiThreadCacheType::NONFOCUS_WINDOW)) {
187             curNode = parentNode;
188         }
189 
190         nodeDrawable_ = std::static_pointer_cast<DrawableV2::RSRenderNodeDrawable>(
191             DrawableV2::RSRenderNodeDrawableAdapter::OnGenerate(curNode));
192         if (IsRectValid(nodeId_, specifiedAreaRect)) {
193             pixelMap_ = CreatePixelMapByRect(specifiedAreaRect);
194         } else {
195             pixelMap_ = CreatePixelMapByNode(curNode);
196         }
197     } else if (auto canvasNode = node->ReinterpretCastTo<RSCanvasRenderNode>()) {
198         nodeDrawable_ = std::static_pointer_cast<DrawableV2::RSRenderNodeDrawable>(
199             DrawableV2::RSRenderNodeDrawableAdapter::OnGenerate(canvasNode));
200         if (IsRectValid(nodeId_, specifiedAreaRect)) {
201             pixelMap_ = CreatePixelMapByRect(specifiedAreaRect);
202         } else {
203             pixelMap_ = CreatePixelMapByNode(canvasNode);
204         }
205     } else {
206         RS_LOGE("RSUiCaptureTaskParallel::CreateResources: Invalid RSRenderNode!");
207         return false;
208     }
209     if (pixelMap_ == nullptr) {
210         RS_LOGE("RSUiCaptureTaskParallel::CreateResources: pixelMap_ is nullptr!");
211         return false;
212     }
213     return true;
214 }
215 
Run(sptr<RSISurfaceCaptureCallback> callback,const Drawing::Rect & specifiedAreaRect)216 bool RSUiCaptureTaskParallel::Run(sptr<RSISurfaceCaptureCallback> callback, const Drawing::Rect& specifiedAreaRect)
217 {
218     RS_TRACE_NAME_FMT("RSUiCaptureTaskParallel::TakeSurfaceCapture. NodeId: [%" PRIu64 "], from pid: [%d]",
219         nodeId_, ExtractPid(nodeId_));
220 
221 #if defined(RS_ENABLE_GL) || defined(RS_ENABLE_VK)
222     auto renderContext = RSUniRenderThread::Instance().GetRenderEngine()->GetRenderContext();
223     auto grContext = renderContext != nullptr ? renderContext->GetDrGPUContext() : nullptr;
224     std::string nodeName("RSUiCaptureTaskParallel");
225     RSTagTracker tagTracker(grContext, nodeId_, RSTagTracker::TAGTYPE::TAG_CAPTURE, nodeName);
226 #endif
227     auto surface = CreateSurface(pixelMap_);
228     if (surface == nullptr) {
229         RS_LOGE("RSUiCaptureTaskParallel::Run: surface is nullptr!");
230         return false;
231     }
232     if (!nodeDrawable_) {
233         RS_LOGE("RSUiCaptureTaskParallel::Run: Invalid RSRenderNodeDrawable!");
234         return false;
235     }
236 
237     RSPaintFilterCanvas canvas(surface.get());
238     canvas.Scale(captureConfig_.scaleX, captureConfig_.scaleY);
239     canvas.SetDisableFilterCache(true);
240     canvas.SetUICapture(true);
241     const auto& nodeParams = nodeDrawable_->GetRenderParams();
242     if (UNLIKELY(!nodeParams)) {
243         RS_LOGE("RSUiCaptureTaskParallel::Run: RenderParams is nullptr!");
244         return false;
245     }
246     Drawing::Matrix relativeMatrix = Drawing::Matrix();
247     relativeMatrix.Set(Drawing::Matrix::Index::SCALE_X, captureConfig_.scaleX);
248     relativeMatrix.Set(Drawing::Matrix::Index::SCALE_Y, captureConfig_.scaleY);
249     int32_t rectLeft = specifiedAreaRect.GetLeft();
250     int32_t rectTop = specifiedAreaRect.GetTop();
251     const Drawing::scalar x_offset = static_cast<Drawing::scalar>(-1 * rectLeft);
252     const Drawing::scalar y_offset = static_cast<Drawing::scalar>(-1 * rectTop);
253     relativeMatrix.Set(Drawing::Matrix::Index::TRANS_X, x_offset);
254     relativeMatrix.Set(Drawing::Matrix::Index::TRANS_Y, y_offset);
255     RS_LOGD("RSUiCaptureTaskParallel::Run: specifiedAreaRect offsetX is [%{public}f], offsetY is [%{public}f]",
256         x_offset, y_offset);
257     Drawing::Matrix invertMatrix;
258     if (nodeParams->GetMatrix().Invert(invertMatrix)) {
259         relativeMatrix.PreConcat(invertMatrix);
260     }
261     canvas.SetMatrix(relativeMatrix);
262 
263     RSUiFirstProcessStateCheckerHelper stateCheckerHepler(
264         nodeParams->GetFirstLevelNodeId(), nodeParams->GetUifirstRootNodeId());
265     RSUniRenderThread::SetCaptureParam(CaptureParam(true, true, false));
266     nodeDrawable_->OnCapture(canvas);
267     RSUniRenderThread::ResetCaptureParam();
268 
269 #if (defined (RS_ENABLE_GL) || defined (RS_ENABLE_VK)) && (defined RS_ENABLE_EGLIMAGE)
270 #ifdef RS_ENABLE_UNI_RENDER
271     bool snapshotDmaEnabled = system::GetBoolParameter("rosen.snapshotDma.enabled", true);
272     bool isEnableFeature = GetFeatureParamValue("CaptureConfig",
273         &CaptureBaseParam::IsSnapshotWithDMAEnabled).value_or(false);
274     if (snapshotDmaEnabled && isEnableFeature) {
275         RSUniRenderUtil::OptimizedFlushAndSubmit(surface, grContext, GetFeatureParamValue("UICaptureConfig",
276             &UICaptureParam::IsUseOptimizedFlushAndSubmitEnabled).value_or(false));
277         auto copytask =
278             RSUiCaptureTaskParallel::CreateSurfaceSyncCopyTask(
279                 surface, std::move(pixelMap_), nodeId_, captureConfig_, callback);
280         if (!copytask) {
281             RS_LOGE("RSUiCaptureTaskParallel::Run: create capture task failed!");
282             return false;
283         }
284         RSBackgroundThread::Instance().PostTask(copytask);
285         return true;
286     } else {
287         std::shared_ptr<Drawing::Image> img(surface.get()->GetImageSnapshot());
288         if (!img) {
289             RS_LOGE("RSUiCaptureTaskParallel::Run: img is nullptr");
290             return false;
291         }
292         if (!CopyDataToPixelMap(img, pixelMap_)) {
293             RS_LOGE("RSUiCaptureTaskParallel::Run: CopyDataToPixelMap failed");
294             return false;
295         }
296     }
297 #endif
298 #endif
299     // To get dump image
300     // execute "param set rosen.dumpsurfacetype.enabled 3 && setenforce 0"
301     RSBaseRenderUtil::WritePixelMapToPng(*pixelMap_);
302     RS_LOGI("RSUiCaptureTaskParallel::Capture DMADisable capture success nodeId:[%{public}" PRIu64
303             "], pixelMap width: %{public}d, height: %{public}d",
304         nodeId_, pixelMap_->GetWidth(), pixelMap_->GetHeight());
305     ProcessUiCaptureCallback(callback, nodeId_, captureConfig_, pixelMap_.get());
306     return true;
307 }
308 
CreatePixelMapByRect(const Drawing::Rect & specifiedAreaRect) const309 std::unique_ptr<Media::PixelMap> RSUiCaptureTaskParallel::CreatePixelMapByRect(
310     const Drawing::Rect& specifiedAreaRect) const
311 {
312     float pixmapWidth = specifiedAreaRect.GetWidth();
313     float pixmapHeight = specifiedAreaRect.GetHeight();
314     Media::InitializationOptions opts;
315     opts.size.width = ceil(pixmapWidth * captureConfig_.scaleX);
316     opts.size.height = ceil(pixmapHeight * captureConfig_.scaleY);
317     RS_LOGD("RSUiCaptureTaskParallel::CreatePixelMapByRect:"
318         " origin pixelmap width is [%{public}f], height is [%{public}f],"
319         " created pixelmap width is [%{public}u], height is [%{public}u],"
320         " the scale is scaleX:[%{public}f], scaleY:[%{public}f]",
321         pixmapWidth, pixmapHeight, opts.size.width, opts.size.height,
322         captureConfig_.scaleX, captureConfig_.scaleY);
323     return Media::PixelMap::Create(opts);
324 }
325 
CreatePixelMapByNode(std::shared_ptr<RSRenderNode> node) const326 std::unique_ptr<Media::PixelMap> RSUiCaptureTaskParallel::CreatePixelMapByNode(
327     std::shared_ptr<RSRenderNode> node) const
328 {
329     float pixmapWidth = node->GetRenderProperties().GetBoundsWidth();
330     float pixmapHeight = node->GetRenderProperties().GetBoundsHeight();
331     Media::InitializationOptions opts;
332     opts.size.width = ceil(pixmapWidth * captureConfig_.scaleX);
333     opts.size.height = ceil(pixmapHeight * captureConfig_.scaleY);
334     RS_LOGD("RSUiCaptureTaskParallel::CreatePixelMapByNode: NodeId:[%{public}" PRIu64 "],"
335         " origin pixelmap width is [%{public}f], height is [%{public}f],"
336         " created pixelmap width is [%{public}u], height is [%{public}u],"
337         " the scale is scaleX:[%{public}f], scaleY:[%{public}f]",
338         node->GetId(), pixmapWidth, pixmapHeight, opts.size.width, opts.size.height,
339         captureConfig_.scaleX, captureConfig_.scaleY);
340     return Media::PixelMap::Create(opts);
341 }
342 
CreateSurface(const std::unique_ptr<Media::PixelMap> & pixelmap) const343 std::shared_ptr<Drawing::Surface> RSUiCaptureTaskParallel::CreateSurface(
344     const std::unique_ptr<Media::PixelMap>& pixelmap) const
345 {
346     if (pixelmap == nullptr) {
347         RS_LOGE("RSUiCaptureTaskParallel::CreateSurface: pixelmap == nullptr");
348         return nullptr;
349     }
350     auto address = const_cast<uint32_t*>(pixelmap->GetPixel32(0, 0));
351     if (address == nullptr) {
352         RS_LOGE("RSUiCaptureTaskParallel::CreateSurface: address == nullptr");
353         return nullptr;
354     }
355     Drawing::ImageInfo info = Drawing::ImageInfo{pixelmap->GetWidth(), pixelmap->GetHeight(),
356         Drawing::ColorType::COLORTYPE_RGBA_8888, Drawing::AlphaType::ALPHATYPE_PREMUL};
357 
358 #if (defined RS_ENABLE_GL) && (defined RS_ENABLE_EGLIMAGE)
359     if (RSSystemProperties::GetGpuApiType() == GpuApiType::OPENGL) {
360         auto renderContext = RSUniRenderThread::Instance().GetRenderEngine()->GetRenderContext();
361         if (renderContext == nullptr) {
362             RS_LOGE("RSUiCaptureTaskParallel::CreateSurface: renderContext is nullptr");
363             return nullptr;
364         }
365         renderContext->SetUpGpuContext(nullptr);
366         return Drawing::Surface::MakeRenderTarget(renderContext->GetDrGPUContext(), false, info);
367     }
368 #endif
369 #ifdef RS_ENABLE_VK
370     if (RSSystemProperties::GetGpuApiType() == GpuApiType::VULKAN ||
371         RSSystemProperties::GetGpuApiType() == GpuApiType::DDGR) {
372         return Drawing::Surface::MakeRenderTarget(
373             RSUniRenderThread::Instance().GetRenderEngine()->GetSkContext().get(), false, info);
374     }
375 #endif
376 
377     return Drawing::Surface::MakeRasterDirect(info, address, pixelmap->GetRowBytes());
378 }
379 
380 #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)381 std::function<void()> RSUiCaptureTaskParallel::CreateSurfaceSyncCopyTask(
382     std::shared_ptr<Drawing::Surface> surface, std::unique_ptr<Media::PixelMap> pixelMap,
383     NodeId id, const RSSurfaceCaptureConfig& captureConfig, sptr<RSISurfaceCaptureCallback> callback,
384     int32_t rotation)
385 {
386     Drawing::BackendTexture backendTexture = surface->GetBackendTexture();
387     if (!backendTexture.IsValid()) {
388         RS_LOGE("RSUiCaptureTaskParallel: SkiaSurface bind Image failed: BackendTexture is invalid");
389         return {};
390     }
391     auto wrapper = std::make_shared<std::tuple<std::unique_ptr<Media::PixelMap>>>();
392     std::get<0>(*wrapper) = std::move(pixelMap);
393     auto wrapperSf = std::make_shared<std::tuple<std::shared_ptr<Drawing::Surface>>>();
394     std::get<0>(*wrapperSf) = std::move(surface);
395     std::function<void()> copytask = [
396         wrapper, captureConfig, callback, backendTexture, wrapperSf, id, rotation]() -> void {
397         RS_TRACE_NAME_FMT("copy and send capture useDma:%d", captureConfig.useDma);
398         if (!backendTexture.IsValid()) {
399             RS_LOGE("RSUiCaptureTaskParallel: Surface bind Image failed: BackendTexture is invalid");
400             ProcessUiCaptureCallback(callback, id, captureConfig, nullptr);
401             RSUniRenderUtil::ClearNodeCacheSurface(
402                 std::move(std::get<0>(*wrapperSf)), nullptr, UNI_MAIN_THREAD_INDEX, 0);
403             return;
404         }
405         auto pixelmap = std::move(std::get<0>(*wrapper));
406         if (pixelmap == nullptr) {
407             RS_LOGE("RSUiCaptureTaskParallel: pixelmap == nullptr");
408             ProcessUiCaptureCallback(callback, id, captureConfig, nullptr);
409             RSUniRenderUtil::ClearNodeCacheSurface(
410                 std::move(std::get<0>(*wrapperSf)), nullptr, UNI_MAIN_THREAD_INDEX, 0);
411             return;
412         }
413 
414         Drawing::ImageInfo info = Drawing::ImageInfo{ pixelmap->GetWidth(), pixelmap->GetHeight(),
415             Drawing::COLORTYPE_RGBA_8888, Drawing::ALPHATYPE_PREMUL };
416         Drawing::TextureOrigin textureOrigin = Drawing::TextureOrigin::BOTTOM_LEFT;
417         Drawing::BitmapFormat bitmapFormat =
418             Drawing::BitmapFormat{ Drawing::COLORTYPE_RGBA_8888, Drawing::ALPHATYPE_PREMUL };
419         std::shared_ptr<Drawing::Surface> surface;
420         auto grContext = RSBackgroundThread::Instance().GetShareGPUContext();
421         if (!grContext) {
422             RS_LOGE("RSUiCaptureTaskParallel: SharedGPUContext get failed");
423             ProcessUiCaptureCallback(callback, id, captureConfig, nullptr);
424             return;
425         }
426 #if defined(ROSEN_OHOS) && defined(RS_ENABLE_VK)
427         DmaMem dmaMem;
428         if (captureConfig.useDma && GetFeatureParamValue("UICaptureConfig",
429             &UICaptureParam::IsUseDMAProcessEnabled).value_or(false) &&
430             (RSSystemProperties::GetGpuApiType() == GpuApiType::VULKAN ||
431             RSSystemProperties::GetGpuApiType() == GpuApiType::DDGR)) {
432             sptr<SurfaceBuffer> surfaceBuffer = dmaMem.DmaMemAlloc(info, pixelmap);
433             surface = dmaMem.GetSurfaceFromSurfaceBuffer(surfaceBuffer, grContext);
434             if (surface == nullptr) {
435                 RS_LOGE("RSUiCaptureTaskParallel: GetSurfaceFromSurfaceBuffer fail.");
436                 ProcessUiCaptureCallback(callback, id, captureConfig, nullptr);
437                 RSUniRenderUtil::ClearNodeCacheSurface(
438                     std::move(std::get<0>(*wrapperSf)), nullptr, UNI_MAIN_THREAD_INDEX, 0);
439                 return;
440             }
441             auto tmpImg = std::make_shared<Drawing::Image>();
442             DrawCapturedImg(*tmpImg, *surface, backendTexture, textureOrigin, bitmapFormat);
443         } else {
444 #else
445         {
446 #endif
447             auto tmpImg = std::make_shared<Drawing::Image>();
448             tmpImg->BuildFromTexture(*grContext, backendTexture.GetTextureInfo(),
449                 textureOrigin, bitmapFormat, nullptr);
450             if (!CopyDataToPixelMap(tmpImg, pixelmap)) {
451                 RS_LOGE("RSUiCaptureTaskParallel: CopyDataToPixelMap failed");
452                 ProcessUiCaptureCallback(callback, id, captureConfig, nullptr);
453                 RSUniRenderUtil::ClearNodeCacheSurface(
454                     std::move(std::get<0>(*wrapperSf)), nullptr, UNI_MAIN_THREAD_INDEX, 0);
455                 return;
456             }
457         }
458         if (rotation) {
459             pixelmap->rotate(rotation);
460         }
461         // To get dump image
462         // execute "param set rosen.dumpsurfacetype.enabled 3 && setenforce 0"
463         RSBaseRenderUtil::WritePixelMapToPng(*pixelmap);
464         RS_LOGI("RSUiCaptureTaskParallel::Capture capture success nodeId:[%{public}" PRIu64
465                 "], pixelMap width: %{public}d, height: %{public}d",
466             id, pixelmap->GetWidth(), pixelmap->GetHeight());
467         ProcessUiCaptureCallback(callback, id, captureConfig, pixelmap.get());
468         RSBackgroundThread::Instance().CleanGrResource();
469         RSUniRenderUtil::ClearNodeCacheSurface(
470             std::move(std::get<0>(*wrapperSf)), nullptr, UNI_MAIN_THREAD_INDEX, 0);
471     };
472     return copytask;
473 }
474 #endif
475 
476 void RSUiCaptureTaskParallel::ProcessUiCaptureCallback(sptr<RSISurfaceCaptureCallback> callback, NodeId id,
477     const RSSurfaceCaptureConfig& captureConfig, Media::PixelMap* pixelmap)
478 {
479     callback->OnSurfaceCapture(id, captureConfig, pixelmap);
480     RSUiCaptureTaskParallel::captureCount_--;
481     RSMainThread::Instance()->RequestNextVSync();
482 }
483 } // namespace Rosen
484 } // namespace OHOS
485