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 "pipeline/rs_surface_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 "memory/rs_tag_tracker.h"
28 #include "params/rs_surface_render_params.h"
29 #include "pipeline/rs_base_render_node.h"
30 #include "pipeline/rs_display_render_node.h"
31 #include "pipeline/rs_main_thread.h"
32 #include "pipeline/rs_paint_filter_canvas.h"
33 #include "pipeline/rs_render_service_connection.h"
34 #include "pipeline/rs_surface_render_node.h"
35 #include "pipeline/rs_uifirst_manager.h"
36 #include "pipeline/rs_uni_render_judgement.h"
37 #include "pipeline/rs_uni_render_util.h"
38 #include "platform/common/rs_log.h"
39 #include "platform/drawing/rs_surface.h"
40 #include "render/rs_drawing_filter.h"
41 #include "render/rs_skia_filter.h"
42 #include "rs_base_render_engine.h"
43 #include "screen_manager/rs_screen_manager.h"
44 #include "screen_manager/rs_screen_mode_info.h"
45
46 namespace OHOS {
47 namespace Rosen {
48 namespace {
DrawCapturedImg(Drawing::Image & image,Drawing::Surface & surface,const Drawing::BackendTexture & backendTexture,Drawing::TextureOrigin & textureOrigin,Drawing::BitmapFormat & bitmapFormat)49 inline void DrawCapturedImg(Drawing::Image& image,
50 Drawing::Surface& surface, const Drawing::BackendTexture& backendTexture,
51 Drawing::TextureOrigin& textureOrigin, Drawing::BitmapFormat& bitmapFormat)
52 {
53 RSPaintFilterCanvas canvas(&surface);
54 auto gpuContext = canvas.GetGPUContext();
55 if (gpuContext == nullptr) {
56 RS_LOGE("DrawCapturedImg failed: gpuContext is nullptr");
57 return;
58 }
59 auto colorSpace = surface.GetImageInfo().GetColorSpace();
60 image.BuildFromTexture(*gpuContext, backendTexture.GetTextureInfo(),
61 textureOrigin, bitmapFormat, colorSpace);
62 canvas.DrawImage(image, 0.f, 0.f, Drawing::SamplingOptions());
63 surface.FlushAndSubmit(true);
64 }
65 }
66
CheckModifiers(NodeId id,bool useCurWindow)67 void RSSurfaceCaptureTaskParallel::CheckModifiers(NodeId id, bool useCurWindow)
68 {
69 RS_TRACE_NAME("RSSurfaceCaptureTaskParallel::CheckModifiers");
70 bool needSync = RSMainThread::Instance()->IsOcclusionNodesNeedSync(id, useCurWindow) ||
71 RSMainThread::Instance()->IsHardwareEnabledNodesNeedSync();
72 if (!needSync) {
73 return;
74 }
75 std::function<void()> syncTask = []() -> void {
76 RS_TRACE_NAME("RSSurfaceCaptureTaskParallel::SyncModifiers");
77 auto& pendingSyncNodes = RSMainThread::Instance()->GetContext().pendingSyncNodes_;
78 int skipTimes = 0;
79 for (auto& [id, weakPtr] : pendingSyncNodes) {
80 auto node = weakPtr.lock();
81 if (node == nullptr) {
82 continue;
83 }
84 if (node->GetType() == RSRenderNodeType::SURFACE_NODE) {
85 auto params = static_cast<RSSurfaceRenderParams*>(node->GetStagingRenderParams().get());
86 params->MarkSurfaceCapturePipeline();
87 }
88 if (!RSUifirstManager::Instance().CollectSkipSyncNode(node)) {
89 node->Sync();
90 } else {
91 node->SkipSync();
92 skipTimes++;
93 }
94 }
95 if (skipTimes != 0) {
96 RS_LOGW("RSSurfaceCaptureTaskParallel::CheckModifiers SkipSync times: [%{public}d]", skipTimes);
97 }
98 pendingSyncNodes.clear();
99 RSUifirstManager::Instance().UifirstCurStateClear();
100 };
101 RSUniRenderThread::Instance().PostSyncTask(syncTask);
102 }
103
Capture(NodeId id,sptr<RSISurfaceCaptureCallback> callback,const RSSurfaceCaptureConfig & captureConfig,bool isSystemCalling,bool isFreeze)104 void RSSurfaceCaptureTaskParallel::Capture(NodeId id, sptr<RSISurfaceCaptureCallback> callback,
105 const RSSurfaceCaptureConfig& captureConfig, bool isSystemCalling, bool isFreeze)
106 {
107 if (callback == nullptr) {
108 RS_LOGE("RSSurfaceCaptureTaskParallel::Capture nodeId:[%{public}" PRIu64 "], callback is nullptr", id);
109 return;
110 }
111 std::shared_ptr<RSSurfaceCaptureTaskParallel> captureHandle =
112 std::make_shared<RSSurfaceCaptureTaskParallel>(id, captureConfig);
113 if (captureHandle == nullptr) {
114 RS_LOGD("RSSurfaceCaptureTaskParallel::Capture captureHandle is nullptr!");
115 callback->OnSurfaceCapture(id, nullptr);
116 return;
117 }
118 if (!captureHandle->CreateResources()) {
119 callback->OnSurfaceCapture(id, nullptr);
120 return;
121 }
122
123 std::function<void()> captureTask = [captureHandle, id, callback, isSystemCalling, isFreeze]() -> void {
124 RS_TRACE_NAME("RSSurfaceCaptureTaskParallel::TakeSurfaceCapture");
125 if (!captureHandle->Run(callback, isSystemCalling, isFreeze)) {
126 callback->OnSurfaceCapture(id, nullptr);
127 }
128 };
129 RSUniRenderThread::Instance().PostSyncTask(captureTask);
130 }
131
ClearCacheImageByFreeze(NodeId id)132 void RSSurfaceCaptureTaskParallel::ClearCacheImageByFreeze(NodeId id)
133 {
134 auto node = RSMainThread::Instance()->GetContext().GetNodeMap().GetRenderNode(id);
135 if (node == nullptr) {
136 RS_LOGE("RSSurfaceCaptureTaskParallel::CreateResources: Invalid nodeId:[%{public}" PRIu64 "]", id);
137 return;
138 }
139 if (auto surfaceNode = node->ReinterpretCastTo<RSSurfaceRenderNode>()) {
140 auto surfaceNodeDrawable = std::static_pointer_cast<DrawableV2::RSRenderNodeDrawable>(
141 DrawableV2::RSRenderNodeDrawableAdapter::OnGenerate(surfaceNode));
142 std::function<void()> clearCacheTask = [id, surfaceNodeDrawable]() -> void {
143 surfaceNodeDrawable->SetCacheImageByCapture(nullptr);
144 };
145 RSUniRenderThread::Instance().PostTask(clearCacheTask);
146 }
147 }
148
CreateResources()149 bool RSSurfaceCaptureTaskParallel::CreateResources()
150 {
151 RS_LOGD("RSSurfaceCaptureTaskParallel capture nodeId:[%{public}" PRIu64 "] scaleX:%{public}f"
152 " scaleY:%{public}f useCurWindow:%{public}d", nodeId_, captureConfig_.scaleX,
153 captureConfig_.scaleY, captureConfig_.useCurWindow);
154 if (ROSEN_EQ(captureConfig_.scaleX, 0.f) || ROSEN_EQ(captureConfig_.scaleY, 0.f) ||
155 captureConfig_.scaleX < 0.f || captureConfig_.scaleY < 0.f ||
156 captureConfig_.scaleX > 1.f || captureConfig_.scaleY > 1.f) {
157 RS_LOGE("RSSurfaceCaptureTaskParallel::CreateResources: SurfaceCapture scale is invalid.");
158 return false;
159 }
160 auto node = RSMainThread::Instance()->GetContext().GetNodeMap().GetRenderNode(nodeId_);
161 if (node == nullptr) {
162 RS_LOGE("RSSurfaceCaptureTaskParallel::CreateResources: Invalid nodeId:[%{public}" PRIu64 "]",
163 nodeId_);
164 return false;
165 }
166
167 if (auto surfaceNode = node->ReinterpretCastTo<RSSurfaceRenderNode>()) {
168 surfaceNode_ = surfaceNode;
169 auto curNode = surfaceNode;
170 if (!captureConfig_.useCurWindow) {
171 auto parentNode = RSBaseRenderNode::ReinterpretCast<RSSurfaceRenderNode>(surfaceNode->GetParent().lock());
172 if (parentNode && parentNode->IsLeashWindow() && parentNode->ShouldPaint()) {
173 curNode = parentNode;
174 }
175 }
176 if (!curNode->ShouldPaint()) {
177 RS_LOGE("RSSurfaceCaptureTaskParallel::CreateResources: Node should not paint!");
178 return false;
179 }
180 if (curNode->GetSortedChildren()->size() == 0) {
181 RS_LOGW("RSSurfaceCaptureTaskParallel::CreateResources: curNode has no childrenList!");
182 }
183 surfaceNodeDrawable_ = std::static_pointer_cast<DrawableV2::RSRenderNodeDrawable>(
184 DrawableV2::RSRenderNodeDrawableAdapter::OnGenerate(curNode));
185 pixelMap_ = CreatePixelMapBySurfaceNode(curNode);
186 } else if (auto displayNode = node->ReinterpretCastTo<RSDisplayRenderNode>()) {
187 displayNodeDrawable_ = std::static_pointer_cast<DrawableV2::RSRenderNodeDrawable>(
188 DrawableV2::RSRenderNodeDrawableAdapter::OnGenerate(displayNode));
189 pixelMap_ = CreatePixelMapByDisplayNode(displayNode);
190 } else {
191 RS_LOGE("RSSurfaceCaptureTaskParallel::CreateResources: Invalid RSRenderNodeType!");
192 return false;
193 }
194 if (pixelMap_ == nullptr) {
195 RS_LOGE("RSSurfaceCaptureTaskParallel::CreateResources: pixelMap_ is nullptr!");
196 return false;
197 }
198 return true;
199 }
200
Run(sptr<RSISurfaceCaptureCallback> callback,bool isSystemCalling,bool isFreeze)201 bool RSSurfaceCaptureTaskParallel::Run(
202 sptr<RSISurfaceCaptureCallback> callback, bool isSystemCalling, bool isFreeze)
203 {
204 #if defined(RS_ENABLE_GL) || defined(RS_ENABLE_VK)
205 SetupGpuContext();
206 std::string nodeName("RSSurfaceCaptureTaskParallel");
207 RSTagTracker tagTracker(gpuContext_.get(), nodeId_, RSTagTracker::TAGTYPE::TAG_CAPTURE, nodeName);
208 #endif
209 auto surface = CreateSurface(pixelMap_);
210 if (surface == nullptr) {
211 RS_LOGE("RSSurfaceCaptureTaskParallel::Run: surface is nullptr!");
212 return false;
213 }
214
215 RSPaintFilterCanvas canvas(surface.get());
216 canvas.Scale(captureConfig_.scaleX, captureConfig_.scaleY);
217 if (captureConfig_.screenWidth > 0 && captureConfig_.screenHeight > 0) {
218 canvas.ClipRect({0, 0, captureConfig_.screenWidth, captureConfig_.screenHeight});
219 canvas.Translate(0 - captureConfig_.screenLeft, 0 - captureConfig_.screenTop);
220 }
221 canvas.SetDisableFilterCache(true);
222 RSSurfaceRenderParams* curNodeParams = nullptr;
223 // Currently, capture do not support HDR display
224 canvas.SetCapture(true);
225 if (surfaceNodeDrawable_) {
226 curNodeParams = static_cast<RSSurfaceRenderParams*>(surfaceNodeDrawable_->GetRenderParams().get());
227 RSUiFirstProcessStateCheckerHelper stateCheckerHelper(
228 curNodeParams->GetFirstLevelNodeId(), curNodeParams->GetUifirstRootNodeId());
229 RSUniRenderThread::SetCaptureParam(
230 CaptureParam(true, true, false, captureConfig_.scaleX, captureConfig_.scaleY, true, isSystemCalling));
231 surfaceNodeDrawable_->OnCapture(canvas);
232 if (isFreeze) {
233 surfaceNodeDrawable_->SetCacheImageByCapture(surface->GetImageSnapshot());
234 }
235 } else if (displayNodeDrawable_) {
236 RSUniRenderThread::SetCaptureParam(
237 CaptureParam(true, false, false, captureConfig_.scaleX, captureConfig_.scaleY));
238 displayNodeDrawable_->OnCapture(canvas);
239 } else {
240 RS_LOGE("RSSurfaceCaptureTaskParallel::Run: Invalid RSRenderNodeDrawable!");
241 return false;
242 }
243 RSUniRenderThread::ResetCaptureParam();
244
245 #if (defined (RS_ENABLE_GL) || defined (RS_ENABLE_VK)) && (defined RS_ENABLE_EGLIMAGE)
246 #ifdef RS_ENABLE_UNI_RENDER
247 RSUniRenderUtil::OptimizedFlushAndSubmit(surface, gpuContext_.get(), !RSSystemProperties::IsPcType());
248 if (curNodeParams && curNodeParams->IsNodeToBeCaptured()) {
249 RSUifirstManager::Instance().AddCapturedNodes(curNodeParams->GetId());
250 }
251 if (RSSystemProperties::GetSnapshotWithDMAEnabled()) {
252 auto copytask = CreateSurfaceSyncCopyTask(surface, std::move(pixelMap_),
253 nodeId_, callback, finalRotationAngle_, captureConfig_.useDma);
254 if (!copytask) {
255 RS_LOGE("RSSurfaceCaptureTaskParallel::Run: create capture task failed!");
256 return false;
257 }
258 RSBackgroundThread::Instance().PostTask(copytask);
259 return true;
260 } else {
261 std::shared_ptr<Drawing::Image> img(surface.get()->GetImageSnapshot());
262 if (!img) {
263 RS_LOGE("RSSurfaceCaptureTaskParallel::Run: img is nullptr");
264 return false;
265 }
266 if (!CopyDataToPixelMap(img, pixelMap_, colorSpace_)) {
267 RS_LOGE("RSSurfaceCaptureTaskParallel::Run: CopyDataToPixelMap failed");
268 return false;
269 }
270 }
271 #endif
272 #endif
273 if (finalRotationAngle_) {
274 pixelMap_->rotate(finalRotationAngle_);
275 }
276 // To get dump image
277 // execute "param set rosen.dumpsurfacetype.enabled 3 && setenforce 0"
278 RSBaseRenderUtil::WritePixelMapToPng(*pixelMap_);
279 callback->OnSurfaceCapture(nodeId_, pixelMap_.get());
280 return true;
281 }
282
CreatePixelMapBySurfaceNode(std::shared_ptr<RSSurfaceRenderNode> node)283 std::unique_ptr<Media::PixelMap> RSSurfaceCaptureTaskParallel::CreatePixelMapBySurfaceNode(
284 std::shared_ptr<RSSurfaceRenderNode> node)
285 {
286 if (node == nullptr) {
287 RS_LOGE("RSSurfaceCaptureTaskParallel::CreatePixelMapBySurfaceNode: node == nullptr");
288 return nullptr;
289 }
290 int pixmapWidth = node->GetRenderProperties().GetBoundsWidth();
291 int pixmapHeight = node->GetRenderProperties().GetBoundsHeight();
292
293 Media::InitializationOptions opts;
294 opts.size.width = ceil(pixmapWidth * captureConfig_.scaleX);
295 opts.size.height = ceil(pixmapHeight * captureConfig_.scaleY);
296 // Surface Node currently does not support regional screenshot
297 captureConfig_.screenLeft = 0.0f;
298 captureConfig_.screenTop = 0.0f;
299 captureConfig_.screenWidth = 0.0f;
300 captureConfig_.screenHeight = 0.0f;
301 RS_LOGI("RSSurfaceCaptureTaskParallel::CreatePixelMapBySurfaceNode: NodeId:[%{public}" PRIu64 "],"
302 " origin pixelmap size: [%{public}u, %{public}u],"
303 " scale: [%{public}f, %{public}f],"
304 " useDma: [%{public}d], useCurWindow: [%{public}d],"
305 " isOnTheTree: [%{public}d], isVisible: [%{public}d]",
306 node->GetId(), pixmapWidth, pixmapHeight, captureConfig_.scaleX, captureConfig_.scaleY,
307 captureConfig_.useDma, captureConfig_.useCurWindow, node->IsOnTheTree(),
308 !surfaceNode_->GetVisibleRegion().IsEmpty());
309 return Media::PixelMap::Create(opts);
310 }
311
CreatePixelMapByDisplayNode(std::shared_ptr<RSDisplayRenderNode> node)312 std::unique_ptr<Media::PixelMap> RSSurfaceCaptureTaskParallel::CreatePixelMapByDisplayNode(
313 std::shared_ptr<RSDisplayRenderNode> node)
314 {
315 if (node == nullptr) {
316 RS_LOGE("RSSurfaceCaptureTaskParallel::CreatePixelMapByDisplayNode: node is nullptr");
317 return nullptr;
318 }
319 uint64_t screenId = node->GetScreenId();
320 sptr<RSScreenManager> screenManager = CreateOrGetScreenManager();
321 if (!screenManager) {
322 RS_LOGE("RSSurfaceCaptureTaskParallel::CreatePixelMapByDisplayNode: screenManager is nullptr!");
323 return nullptr;
324 }
325 auto screenInfo = screenManager->QueryScreenInfo(screenId);
326 screenCorrection_ = screenManager->GetScreenCorrection(screenId);
327 screenRotation_ = node->GetScreenRotation();
328 finalRotationAngle_ = CalPixelMapRotation();
329 uint32_t pixmapWidth = screenInfo.width;
330 uint32_t pixmapHeight = screenInfo.height;
331
332 if (captureConfig_.screenWidth > 0 && captureConfig_.screenHeight > 0 &&
333 captureConfig_.screenWidth <= pixmapWidth && captureConfig_.screenHeight <= pixmapHeight) {
334 pixmapWidth = floor(captureConfig_.screenWidth);
335 pixmapHeight = floor(captureConfig_.screenHeight);
336 }
337 Media::InitializationOptions opts;
338 opts.size.width = ceil(pixmapWidth * captureConfig_.scaleX);
339 opts.size.height = ceil(pixmapHeight * captureConfig_.scaleY);
340 RS_LOGI("RSSurfaceCaptureTaskParallel::CreatePixelMapByDisplayNode: NodeId:[%{public}" PRIu64 "],"
341 " origin pixelmap size: [%{public}u, %{public}u],"
342 " scale: [%{public}f, %{public}f],"
343 " ScreenRect: [%{public}f, %{public}f, %{public}f, %{public}f],"
344 " useDma: [%{public}d], screenRotation_: [%{public}d], screenCorrection_: [%{public}d]",
345 node->GetId(), pixmapWidth, pixmapHeight, captureConfig_.scaleX, captureConfig_.scaleY,
346 captureConfig_.screenLeft, captureConfig_.screenTop, captureConfig_.screenWidth, captureConfig_.screenHeight,
347 captureConfig_.useDma, screenRotation_, screenCorrection_);
348 return Media::PixelMap::Create(opts);
349 }
350
CreateSurface(const std::unique_ptr<Media::PixelMap> & pixelmap)351 std::shared_ptr<Drawing::Surface> RSSurfaceCaptureTaskParallel::CreateSurface(
352 const std::unique_ptr<Media::PixelMap>& pixelmap)
353 {
354 if (pixelmap == nullptr) {
355 RS_LOGE("RSSurfaceCaptureTaskParallel::CreateSurface: pixelmap == nullptr");
356 return nullptr;
357 }
358 auto address = const_cast<uint32_t*>(pixelmap->GetPixel32(0, 0));
359 if (address == nullptr) {
360 RS_LOGE("RSSurfaceCaptureTaskParallel::CreateSurface: address == nullptr");
361 return nullptr;
362 }
363 GraphicColorGamut colorGamut = GraphicColorGamut::GRAPHIC_COLOR_GAMUT_SRGB;
364 RSDisplayRenderParams* curNodeParams = nullptr;
365 if (displayNodeDrawable_) {
366 curNodeParams = static_cast<RSDisplayRenderParams*>(displayNodeDrawable_->GetRenderParams().get());
367 colorGamut = curNodeParams->GetNewColorSpace();
368 }
369 colorSpace_ = RSBaseRenderEngine::ConvertColorGamutToDrawingColorSpace(colorGamut);
370 Drawing::ImageInfo info = Drawing::ImageInfo{pixelmap->GetWidth(), pixelmap->GetHeight(),
371 Drawing::ColorType::COLORTYPE_RGBA_8888, Drawing::AlphaType::ALPHATYPE_PREMUL, colorSpace_};
372
373 #if (defined RS_ENABLE_GL) && (defined RS_ENABLE_EGLIMAGE)
374 if (RSSystemProperties::GetGpuApiType() == GpuApiType::OPENGL) {
375 auto renderEngine = RSUniRenderThread::Instance().GetRenderEngine();
376 if (renderEngine == nullptr) {
377 RS_LOGE("RSSurfaceCaptureTaskParallel::CreateSurface: renderEngine is nullptr");
378 return nullptr;
379 }
380 auto renderContext = renderEngine->GetRenderContext();
381 if (renderContext == nullptr) {
382 RS_LOGE("RSSurfaceCaptureTaskParallel::CreateSurface: renderContext is nullptr");
383 return nullptr;
384 }
385 renderContext->SetUpGpuContext(nullptr);
386 return Drawing::Surface::MakeRenderTarget(renderContext->GetDrGPUContext(), false, info);
387 }
388 #endif
389 #ifdef RS_ENABLE_VK
390 if (RSSystemProperties::GetGpuApiType() == GpuApiType::VULKAN ||
391 RSSystemProperties::GetGpuApiType() == GpuApiType::DDGR) {
392 return Drawing::Surface::MakeRenderTarget(gpuContext_.get(), false, info);
393 }
394 #endif
395
396 return Drawing::Surface::MakeRasterDirect(info, address, pixelmap->GetRowBytes());
397 }
398
SetupGpuContext()399 void RSSurfaceCaptureTaskParallel::SetupGpuContext()
400 {
401 auto renderEngine = RSUniRenderThread::Instance().GetRenderEngine();
402 if (renderEngine == nullptr) {
403 RS_LOGE("RSSurfaceCaptureTaskParallel::SetupGpuContext: renderEngine is nullptr");
404 return;
405 }
406 auto renderContext = renderEngine->GetRenderContext();
407 gpuContext_ = renderContext != nullptr ? renderContext->GetSharedDrGPUContext() : nullptr;
408 if (gpuContext_ == nullptr) {
409 RS_LOGW("RSSurfaceCaptureTaskParallel::SetupGpuContext gpuContext_ is nullptr");
410 }
411 }
412
CalPixelMapRotation()413 int32_t RSSurfaceCaptureTaskParallel::CalPixelMapRotation()
414 {
415 auto screenRotation = ScreenRotationMapping(screenRotation_);
416 auto screenCorrection = ScreenRotationMapping(screenCorrection_);
417 int32_t rotation = screenRotation - screenCorrection;
418 return rotation;
419 }
420
421 #ifdef RS_ENABLE_UNI_RENDER
CreateSurfaceSyncCopyTask(std::shared_ptr<Drawing::Surface> surface,std::unique_ptr<Media::PixelMap> pixelMap,NodeId id,sptr<RSISurfaceCaptureCallback> callback,int32_t rotation,bool useDma)422 std::function<void()> RSSurfaceCaptureTaskParallel::CreateSurfaceSyncCopyTask(
423 std::shared_ptr<Drawing::Surface> surface, std::unique_ptr<Media::PixelMap> pixelMap,
424 NodeId id, sptr<RSISurfaceCaptureCallback> callback, int32_t rotation, bool useDma)
425 {
426 if (surface == nullptr) {
427 RS_LOGE("RSSurfaceCaptureTaskParallel: nodeId:[%{public}" PRIu64 "], surface is nullptr", id);
428 return {};
429 }
430 Drawing::BackendTexture backendTexture = surface->GetBackendTexture();
431 if (!backendTexture.IsValid()) {
432 RS_LOGE("RSSurfaceCaptureTaskParallel: SkiaSurface bind Image failed: BackendTexture is invalid");
433 return {};
434 }
435 auto wrapper = std::make_shared<std::tuple<std::unique_ptr<Media::PixelMap>>>();
436 std::get<0>(*wrapper) = std::move(pixelMap);
437 auto wrapperSf = std::make_shared<std::tuple<std::shared_ptr<Drawing::Surface>>>();
438 std::get<0>(*wrapperSf) = std::move(surface);
439 std::function<void()> copytask = [wrapper, callback, backendTexture, wrapperSf, id, rotation, useDma]() -> void {
440 RS_TRACE_NAME_FMT("copy and send capture useDma:%d", useDma);
441 if (callback == nullptr) {
442 RS_LOGE("RSSurfaceCaptureTaskParallel: nodeId:[%{public}" PRIu64 "], callback is nullptr", id);
443 return;
444 }
445 auto colorSpace = std::get<0>(*wrapperSf)->GetImageInfo().GetColorSpace();
446 if (!backendTexture.IsValid()) {
447 RS_LOGE("RSSurfaceCaptureTaskParallel: Surface bind Image failed: BackendTexture is invalid");
448 callback->OnSurfaceCapture(id, nullptr);
449 RSUniRenderUtil::ClearNodeCacheSurface(
450 std::move(std::get<0>(*wrapperSf)), nullptr, UNI_MAIN_THREAD_INDEX, 0);
451 return;
452 }
453 auto pixelmap = std::move(std::get<0>(*wrapper));
454 if (pixelmap == nullptr) {
455 RS_LOGE("RSSurfaceCaptureTaskParallel: pixelmap == nullptr");
456 callback->OnSurfaceCapture(id, nullptr);
457 RSUniRenderUtil::ClearNodeCacheSurface(
458 std::move(std::get<0>(*wrapperSf)), nullptr, UNI_MAIN_THREAD_INDEX, 0);
459 return;
460 }
461
462 Drawing::ImageInfo info = Drawing::ImageInfo{ pixelmap->GetWidth(), pixelmap->GetHeight(),
463 Drawing::COLORTYPE_RGBA_8888, Drawing::ALPHATYPE_PREMUL, colorSpace};
464 Drawing::TextureOrigin textureOrigin = Drawing::TextureOrigin::BOTTOM_LEFT;
465 Drawing::BitmapFormat bitmapFormat =
466 Drawing::BitmapFormat{ Drawing::COLORTYPE_RGBA_8888, Drawing::ALPHATYPE_PREMUL };
467 std::shared_ptr<Drawing::Surface> surface;
468 auto grContext = RSBackgroundThread::Instance().GetShareGPUContext();
469 #if defined(ROSEN_OHOS) && defined(RS_ENABLE_VK)
470 DmaMem dmaMem;
471 if (useDma && RSMainThread::Instance()->GetDeviceType() == DeviceType::PHONE &&
472 (RSSystemProperties::GetGpuApiType() == GpuApiType::VULKAN ||
473 RSSystemProperties::GetGpuApiType() == GpuApiType::DDGR)) {
474 sptr<SurfaceBuffer> surfaceBuffer = dmaMem.DmaMemAlloc(info, pixelmap);
475 if (surfaceBuffer != nullptr && colorSpace != nullptr && !colorSpace->IsSRGB()) {
476 surfaceBuffer->SetSurfaceBufferColorGamut(GraphicColorGamut::GRAPHIC_COLOR_GAMUT_DISPLAY_P3);
477 }
478 surface = dmaMem.GetSurfaceFromSurfaceBuffer(surfaceBuffer, grContext);
479 if (surface == nullptr) {
480 RS_LOGE("RSSurfaceCaptureTaskParallel: GetSurfaceFromSurfaceBuffer fail.");
481 callback->OnSurfaceCapture(id, nullptr);
482 RSUniRenderUtil::ClearNodeCacheSurface(
483 std::move(std::get<0>(*wrapperSf)), nullptr, UNI_MAIN_THREAD_INDEX, 0);
484 return;
485 }
486 auto tmpImg = std::make_shared<Drawing::Image>();
487 DrawCapturedImg(*tmpImg, *surface, backendTexture, textureOrigin, bitmapFormat);
488 } else {
489 #else
490 {
491 #endif
492 auto tmpImg = std::make_shared<Drawing::Image>();
493 tmpImg->BuildFromTexture(*grContext, backendTexture.GetTextureInfo(),
494 textureOrigin, bitmapFormat, colorSpace);
495 if (!CopyDataToPixelMap(tmpImg, pixelmap, colorSpace)) {
496 RS_LOGE("RSSurfaceCaptureTaskParallel: CopyDataToPixelMap failed");
497 callback->OnSurfaceCapture(id, nullptr);
498 RSUniRenderUtil::ClearNodeCacheSurface(
499 std::move(std::get<0>(*wrapperSf)), nullptr, UNI_MAIN_THREAD_INDEX, 0);
500 return;
501 }
502 }
503 if (rotation) {
504 pixelmap->rotate(rotation);
505 }
506 // To get dump image
507 // execute "param set rosen.dumpsurfacetype.enabled 3 && setenforce 0"
508 RSBaseRenderUtil::WritePixelMapToPng(*pixelmap);
509 callback->OnSurfaceCapture(id, pixelmap.get());
510 RSBackgroundThread::Instance().CleanGrResource();
511 RSUniRenderUtil::ClearNodeCacheSurface(
512 std::move(std::get<0>(*wrapperSf)), nullptr, UNI_MAIN_THREAD_INDEX, 0);
513 };
514 return copytask;
515 }
516 #endif
517
518 #if defined(ROSEN_OHOS) && defined(RS_ENABLE_VK)
519 DmaMem::~DmaMem()
520 {
521 ReleaseDmaMemory();
522 }
523
524 void DmaMem::ReleaseDmaMemory()
525 {
526 if (nativeWindowBuffer_ != nullptr) {
527 DestroyNativeWindowBuffer(nativeWindowBuffer_);
528 nativeWindowBuffer_ = nullptr;
529 }
530 }
531
532 sptr<SurfaceBuffer> DmaMem::DmaMemAlloc(Drawing::ImageInfo &dstInfo, const std::unique_ptr<Media::PixelMap>& pixelmap)
533 {
534 #if defined(_WIN32) || defined(_APPLE) || defined(A_PLATFORM) || defined(IOS_PLATFORM)
535 RS_LOGE("Unsupport dma mem alloc");
536 return nullptr;
537 #else
538 if (pixelmap == nullptr) {
539 RS_LOGE("DmaMem::DmaMemAlloc: pixelmap is nullptr");
540 return nullptr;
541 }
542 sptr<SurfaceBuffer> surfaceBuffer = SurfaceBuffer::Create();
543 if (!surfaceBuffer) {
544 RS_LOGE("DmaMem::DmaMemAlloc: surfaceBuffer create failed");
545 return nullptr;
546 }
547 BufferRequestConfig requestConfig = {
548 .width = dstInfo.GetWidth(),
549 .height = dstInfo.GetHeight(),
550 .strideAlignment = 0x8, // set 0x8 as default value to alloc SurfaceBufferImpl
551 .format = GRAPHIC_PIXEL_FMT_RGBA_8888, // PixelFormat
552 .usage = BUFFER_USAGE_CPU_READ | BUFFER_USAGE_HW_RENDER | BUFFER_USAGE_HW_TEXTURE | BUFFER_USAGE_MEM_DMA,
553 .timeout = 0,
554 .colorGamut = GraphicColorGamut::GRAPHIC_COLOR_GAMUT_SRGB,
555 .transform = GraphicTransformType::GRAPHIC_ROTATE_NONE,
556 };
557 GSError ret = surfaceBuffer->Alloc(requestConfig);
558 if (ret != GSERROR_OK) {
559 RS_LOGE("DmaMem::DmaMemAlloc: surfaceBuffer alloc failed, %{public}s", GSErrorStr(ret).c_str());
560 return nullptr;
561 }
562 void* nativeBuffer = surfaceBuffer.GetRefPtr();
563 OHOS::RefBase *ref = reinterpret_cast<OHOS::RefBase *>(nativeBuffer);
564 ref->IncStrongRef(ref);
565 int32_t bufferSize = pixelmap->GetByteCount();
566 pixelmap->SetPixelsAddr(surfaceBuffer->GetVirAddr(), nativeBuffer, bufferSize,
567 Media::AllocatorType::DMA_ALLOC, nullptr);
568 return surfaceBuffer;
569 #endif
570 }
571
572 static inline void DeleteVkImage(void *context)
573 {
574 NativeBufferUtils::VulkanCleanupHelper *cleanupHelper =
575 static_cast<NativeBufferUtils::VulkanCleanupHelper *> (context);
576 if (cleanupHelper != nullptr) {
577 cleanupHelper->UnRef();
578 }
579 }
580
581 std::shared_ptr<Drawing::Surface> DmaMem::GetSurfaceFromSurfaceBuffer(
582 sptr<SurfaceBuffer> surfaceBuffer, std::shared_ptr<Drawing::GPUContext> gpuContext)
583 {
584 if (surfaceBuffer == nullptr || gpuContext == nullptr) {
585 RS_LOGE("GetSurfaceFromSurfaceBuffer surfaceBuffer or gpuContext is nullptr");
586 return nullptr;
587 }
588 if (nativeWindowBuffer_ == nullptr) {
589 nativeWindowBuffer_ = CreateNativeWindowBufferFromSurfaceBuffer(&surfaceBuffer);
590 if (!nativeWindowBuffer_) {
591 RS_LOGE("DmaMem::GetSurfaceFromSurfaceBuffer: nativeWindowBuffer_ is nullptr");
592 return nullptr;
593 }
594 }
595
596 Drawing::BackendTexture backendTextureTmp =
597 NativeBufferUtils::MakeBackendTextureFromNativeBuffer(nativeWindowBuffer_,
598 surfaceBuffer->GetWidth(), surfaceBuffer->GetHeight());
599 if (!backendTextureTmp.IsValid()) {
600 return nullptr;
601 }
602
603 auto vkTextureInfo = backendTextureTmp.GetTextureInfo().GetVKTextureInfo();
604 if (vkTextureInfo == nullptr) {
605 return nullptr;
606 }
607 vkTextureInfo->imageUsageFlags = vkTextureInfo->imageUsageFlags | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
608 auto cleanUpHelper = new NativeBufferUtils::VulkanCleanupHelper(RsVulkanContext::GetSingleton(),
609 vkTextureInfo->vkImage, vkTextureInfo->vkAlloc.memory);
610 if (cleanUpHelper == nullptr) {
611 return nullptr;
612 }
613 // attention: cleanUpHelper will be delete by NativeBufferUtils::DeleteVkImage, don't delete again
614 auto colorSpace =
615 RSBaseRenderEngine::ConvertColorGamutToDrawingColorSpace(surfaceBuffer->GetSurfaceBufferColorGamut());
616 auto drawingSurface = Drawing::Surface::MakeFromBackendTexture(
617 gpuContext.get(),
618 backendTextureTmp.GetTextureInfo(),
619 Drawing::TextureOrigin::TOP_LEFT,
620 1, Drawing::ColorType::COLORTYPE_RGBA_8888, colorSpace,
621 NativeBufferUtils::DeleteVkImage, cleanUpHelper);
622 return drawingSurface;
623 }
624 #endif
625 } // namespace Rosen
626 } // namespace OHOS
627