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