• 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 "drawable/rs_canvas_drawing_render_node_drawable.h"
17 
18 #include "common/rs_background_thread.h"
19 #include "common/rs_common_def.h"
20 #include "include/gpu/vk/GrVulkanTrackerInterface.h"
21 #include "offscreen_render/rs_offscreen_render_thread.h"
22 #include "params/rs_canvas_drawing_render_params.h"
23 #include "pipeline/rs_main_thread.h"
24 #include "pipeline/rs_task_dispatcher.h"
25 #include "pipeline/rs_uni_render_thread.h"
26 #include "pipeline/rs_uni_render_util.h"
27 #include "pipeline/sk_resource_manager.h"
28 #include "pipeline/parallel_render/rs_sub_thread_manager.h"
29 #include "platform/common/rs_log.h"
30 
31 namespace OHOS::Rosen::DrawableV2 {
32 namespace {
33     constexpr int EDGE_WIDTH_LIMIT = 1000;
34     constexpr float DRAW_REGION_FOR_DFX_BORDER = 5.0f;
35 }
36 RSCanvasDrawingRenderNodeDrawable::Registrar RSCanvasDrawingRenderNodeDrawable::instance_;
37 
RSCanvasDrawingRenderNodeDrawable(std::shared_ptr<const RSRenderNode> && node)38 RSCanvasDrawingRenderNodeDrawable::RSCanvasDrawingRenderNodeDrawable(std::shared_ptr<const RSRenderNode>&& node)
39     : RSRenderNodeDrawable(std::move(node))
40 {
41     auto renderNode = renderNode_.lock();
42     if (renderNode == nullptr) {
43         return;
44     }
45     auto nodeSp = std::const_pointer_cast<RSRenderNode>(renderNode);
46     auto canvasDrawingRenderNode = std::static_pointer_cast<RSCanvasDrawingRenderNode>(nodeSp);
47     canvasDrawingRenderNode->InitRenderContent();
48 }
49 
~RSCanvasDrawingRenderNodeDrawable()50 RSCanvasDrawingRenderNodeDrawable::~RSCanvasDrawingRenderNodeDrawable()
51 {
52 #if (defined(RS_ENABLE_GL) || defined(RS_ENABLE_VK))
53     if (curThreadInfo_.second && surface_) {
54         curThreadInfo_.second(std::move(surface_));
55     }
56 #ifdef RS_ENABLE_VK
57     if (RSSystemProperties::GetGpuApiType() == GpuApiType::VULKAN ||
58         RSSystemProperties::GetGpuApiType() == GpuApiType::DDGR) {
59         if (vulkanCleanupHelper_ && isPurge_) {
60             vulkanCleanupHelper_->UnRef();
61             isPurge_ = false;
62         }
63     }
64 #endif
65 #endif
66 }
67 
OnGenerate(std::shared_ptr<const RSRenderNode> node)68 RSRenderNodeDrawable::Ptr RSCanvasDrawingRenderNodeDrawable::OnGenerate(std::shared_ptr<const RSRenderNode> node)
69 {
70     return new RSCanvasDrawingRenderNodeDrawable(std::move(node));
71 }
72 
OnDraw(Drawing::Canvas & canvas)73 void RSCanvasDrawingRenderNodeDrawable::OnDraw(Drawing::Canvas& canvas)
74 {
75     SetDrawSkipType(DrawSkipType::NONE);
76     std::unique_lock<std::recursive_mutex> lock(drawableMutex_);
77     if (!ShouldPaint()) {
78         SetDrawSkipType(DrawSkipType::SHOULD_NOT_PAINT);
79         return;
80     }
81     const auto& params = GetRenderParams();
82     if (UNLIKELY(!params)) {
83         SetDrawSkipType(DrawSkipType::RENDER_PARAMS_NULL);
84         return;
85     }
86     if (params->GetCanvasDrawingSurfaceChanged()) {
87         ResetSurface();
88         params->SetCanvasDrawingSurfaceChanged(false);
89     }
90     auto paintFilterCanvas = static_cast<RSPaintFilterCanvas*>(&canvas);
91     RSAutoCanvasRestore acr(paintFilterCanvas, RSPaintFilterCanvas::SaveType::kCanvasAndAlpha);
92     if (!canvas.GetRecordingState()) {
93         params->ApplyAlphaAndMatrixToCanvas(*paintFilterCanvas);
94     }
95 
96     auto& uniParam = RSUniRenderThread::Instance().GetRSRenderThreadParams();
97     if ((UNLIKELY(!uniParam) || uniParam->IsOpDropped()) && GetOpDropped() &&
98         QuickReject(canvas, params->GetLocalDrawRect())) {
99         SetDrawSkipType(DrawSkipType::OCCLUSION_SKIP);
100         return;
101     }
102 
103     auto threadIdx = paintFilterCanvas->GetParallelThreadIdx();
104     auto clearFunc = [idx = threadIdx](std::shared_ptr<Drawing::Surface> surface) {
105         // The second param is null, 0 is an invalid value.
106         RSUniRenderUtil::ClearNodeCacheSurface(std::move(surface), nullptr, idx, 0);
107     };
108     auto threadId = paintFilterCanvas->GetIsParallelCanvas() ?
109         RSSubThreadManager::Instance()->GetReThreadIndexMap()[threadIdx] : RSUniRenderThread::Instance().GetTid();
110     SetSurfaceClearFunc({ threadIdx, clearFunc }, threadId);
111 
112     auto& bounds = params->GetBounds();
113     auto surfaceParams = params->GetCanvasDrawingSurfaceParams();
114     if (!InitSurface(surfaceParams.width, surfaceParams.height, *paintFilterCanvas)) {
115         SetDrawSkipType(DrawSkipType::INIT_SURFACE_FAIL);
116         RS_LOGE("Failed to init surface!");
117         return;
118     }
119 
120     // 1. Draw background of this drawing node by the main canvas.
121     DrawBackground(canvas, bounds);
122 
123     // 2. Draw content of this drawing node by the content canvas.
124     DrawRenderContent(canvas, bounds);
125 
126     // 3. Draw children of this drawing node by the main canvas.
127     DrawChildren(canvas, bounds);
128 
129     // 4. Draw foreground of this drawing node by the main canvas.
130     DrawForeground(canvas, bounds);
131 
132     // 5. Ready to clear resource.
133     SetDrawCmdListsVisited(true);
134 
135     // Draw bounds rect for dfx.
136     DrawRegionForDfx(canvas, bounds);
137 }
138 
DrawRenderContent(Drawing::Canvas & canvas,const Drawing::Rect & rect)139 void RSCanvasDrawingRenderNodeDrawable::DrawRenderContent(Drawing::Canvas& canvas, const Drawing::Rect& rect)
140 {
141     DrawContent(*canvas_, rect);
142     if (!renderParams_) {
143         return;
144     }
145     renderParams_->SetNeedProcess(false);
146     Rosen::Drawing::Matrix mat;
147     const auto& params = GetRenderParams();
148     if (params == nullptr) {
149         return;
150     }
151     auto& frameRect = params->GetFrameRect();
152     if (RSPropertiesPainter::GetGravityMatrix(params->GetFrameGravity(),
153         { frameRect.GetLeft(), frameRect.GetTop(), frameRect.GetWidth(), frameRect.GetHeight() },
154         params->GetBounds().GetWidth(), params->GetBounds().GetHeight(), mat)) {
155         canvas.ConcatMatrix(mat);
156     }
157     auto ctx = RSUniRenderThread::Instance().GetRSRenderThreadParams()->GetContext();
158     Flush(rect.GetWidth(), rect.GetHeight(), ctx, nodeId_,
159         *static_cast<RSPaintFilterCanvas*>(&canvas)); // getimage
160     if (image_ == nullptr) {
161         RS_LOGD("Failed to draw gpu image!");
162         return;
163     }
164 
165     auto samplingOptions = Drawing::SamplingOptions(Drawing::FilterMode::LINEAR,
166         Drawing::MipmapMode::LINEAR);
167     Drawing::Paint paint;
168     paint.SetStyle(Drawing::Paint::PaintStyle::PAINT_FILL);
169     canvas.AttachPaint(paint);
170     canvas.DrawImage(*image_, 0.f, 0.f, samplingOptions);
171     canvas.DetachPaint();
172 }
173 
OnCapture(Drawing::Canvas & canvas)174 void RSCanvasDrawingRenderNodeDrawable::OnCapture(Drawing::Canvas& canvas)
175 {
176     OnDraw(canvas);
177 }
178 
Purge()179 void RSCanvasDrawingRenderNodeDrawable::Purge()
180 {
181 #ifdef RS_ENABLE_VK
182     std::unique_lock<std::recursive_mutex> lock(drawableMutex_);
183     if (curThreadInfo_.second && surface_) {
184         curThreadInfo_.second(std::move(surface_));
185         surface_ = nullptr;
186         if (RSSystemProperties::GetGpuApiType() == GpuApiType::VULKAN ||
187             RSSystemProperties::GetGpuApiType() == GpuApiType::DDGR) {
188             if (vulkanCleanupHelper_ && !isPurge_) {
189                 vulkanCleanupHelper_->Ref();
190                 isPurge_ = true;
191             }
192         }
193     }
194 #endif
195     RSRenderNodeDrawableAdapter::Purge();
196 }
197 
PlaybackInCorrespondThread()198 void RSCanvasDrawingRenderNodeDrawable::PlaybackInCorrespondThread()
199 {
200     auto canvasDrawingPtr = shared_from_this();
201     pid_t threadId = threadId_;
202     auto task = [this, canvasDrawingPtr, threadId]() {
203         std::unique_lock<std::recursive_mutex> lock(drawableMutex_);
204         if (!surface_ || !canvas_ || !renderParams_ || threadId != threadId_) {
205             return;
206         }
207         if (renderParams_->GetCanvasDrawingSurfaceChanged()) {
208             return;
209         }
210         auto rect = GetRenderParams()->GetBounds();
211         DrawContent(*canvas_, rect);
212         renderParams_->SetNeedProcess(false);
213         canvas_->Flush();
214         SetDrawCmdListsVisited(true);
215     };
216     RSTaskDispatcher::GetInstance().PostTask(threadId, task, false);
217 }
218 
InitSurface(int width,int height,RSPaintFilterCanvas & canvas)219 bool RSCanvasDrawingRenderNodeDrawable::InitSurface(int width, int height, RSPaintFilterCanvas& canvas)
220 {
221 #if defined(RS_ENABLE_GL) || defined(RS_ENABLE_VK)
222     if (RSSystemProperties::GetGpuApiType() == GpuApiType::OPENGL) {
223         return InitSurfaceForGL(width, height, canvas);
224     }
225     if (RSSystemProperties::GetGpuApiType() == GpuApiType::VULKAN ||
226         RSSystemProperties::GetGpuApiType() == GpuApiType::DDGR) {
227         return InitSurfaceForVK(width, height, canvas);
228     }
229 #endif
230     return false;
231 }
232 
InitSurfaceForGL(int width,int height,RSPaintFilterCanvas & canvas)233 bool RSCanvasDrawingRenderNodeDrawable::InitSurfaceForGL(int width, int height, RSPaintFilterCanvas& canvas)
234 {
235     if (IsNeedResetSurface()) {
236         ClearPreSurface(surface_);
237         preThreadInfo_ = curThreadInfo_;
238         if (!ResetSurfaceForGL(width, height, canvas)) {
239             return false;
240         }
241     } else if ((isGpuSurface_) && (preThreadInfo_.first != curThreadInfo_.first)) {
242         if (!ResetSurfaceWithTexture(width, height, canvas)) {
243             return false;
244         }
245     }
246     if (!surface_) {
247         return false;
248     }
249     return true;
250 }
251 
InitSurfaceForVK(int width,int height,RSPaintFilterCanvas & canvas)252 bool RSCanvasDrawingRenderNodeDrawable::InitSurfaceForVK(int width, int height, RSPaintFilterCanvas& canvas)
253 {
254     if (IsNeedResetSurface()) {
255         ClearPreSurface(surface_);
256         preThreadInfo_ = curThreadInfo_;
257         if (!ResetSurfaceForVK(width, height, canvas)) {
258             return false;
259         }
260     } else if ((isGpuSurface_) && (preThreadInfo_.first != curThreadInfo_.first)) {
261         if (!ReuseBackendTexture(width, height, canvas)) {
262             return false;
263         }
264     }
265     if (!surface_) {
266         return false;
267     }
268     return true;
269 }
270 
FlushForGL(float width,float height,std::shared_ptr<RSContext> context,NodeId nodeId,RSPaintFilterCanvas & rscanvas)271 void RSCanvasDrawingRenderNodeDrawable::FlushForGL(float width, float height, std::shared_ptr<RSContext> context,
272     NodeId nodeId, RSPaintFilterCanvas& rscanvas)
273 {
274     if (!recordingCanvas_) {
275         if (rscanvas.GetParallelThreadIdx() != curThreadInfo_.first) {
276             if (!backendTexture_.IsValid()) {
277                 RS_LOGE("RSCanvasDrawingRenderNodeDrawable::Flush backendTexture_ is nullptr");
278                 return;
279             }
280             if (rscanvas.GetGPUContext() == nullptr) {
281                 RS_LOGE("RSCanvasDrawingRenderNodeDrawable::Flush GPU context is nullptr");
282                 return;
283             }
284             Drawing::TextureOrigin origin = GetTextureOrigin();
285             Drawing::BitmapFormat info = Drawing::BitmapFormat{ image_->GetColorType(), image_->GetAlphaType() };
286             SharedTextureContext* sharedContext = new SharedTextureContext(image_); // last image
287             image_ = std::make_shared<Drawing::Image>();
288             ReleaseCaptureImage();
289             bool ret = image_->BuildFromTexture(*rscanvas.GetGPUContext(), backendTexture_.GetTextureInfo(), origin,
290                 info, nullptr, SKResourceManager::DeleteSharedTextureContext, sharedContext);
291             if (!ret) {
292                 RS_LOGE("RSCanvasDrawingRenderNodeDrawable::Flush image BuildFromTexture failed");
293                 return;
294             }
295         } else {
296             image_ = surface_->GetImageSnapshot(); // planning: return image_
297             backendTexture_ = surface_->GetBackendTexture();
298             ReleaseCaptureImage();
299             if (!backendTexture_.IsValid()) {
300                 RS_LOGE("RSCanvasDrawingRenderNodeDrawable::Flush !backendTexture_.IsValid() %d", __LINE__);
301             }
302         }
303 
304         if (image_) {
305             SKResourceManager::Instance().HoldResource(image_);
306         }
307     } else {
308         auto cmds = recordingCanvas_->GetDrawCmdList();
309         if (cmds && !cmds->IsEmpty()) {
310             recordingCanvas_ = std::make_shared<ExtendRecordingCanvas>(width, height, false);
311             canvas_ = std::make_unique<RSPaintFilterCanvas>(recordingCanvas_.get());
312             ProcessCPURenderInBackgroundThread(cmds, context, nodeId);
313         }
314     }
315 }
316 
FlushForVK(float width,float height,std::shared_ptr<RSContext> context,NodeId nodeId,RSPaintFilterCanvas & rscanvas)317 void RSCanvasDrawingRenderNodeDrawable::FlushForVK(float width, float height, std::shared_ptr<RSContext> context,
318     NodeId nodeId, RSPaintFilterCanvas& rscanvas)
319 {
320     if (!recordingCanvas_) {
321         REAL_ALLOC_CONFIG_SET_STATUS(true);
322         image_ = surface_->GetImageSnapshot();
323         REAL_ALLOC_CONFIG_SET_STATUS(false);
324     } else {
325         auto cmds = recordingCanvas_->GetDrawCmdList();
326         if (cmds && !cmds->IsEmpty()) {
327             recordingCanvas_ = std::make_shared<ExtendRecordingCanvas>(width, height, false);
328             canvas_ = std::make_unique<RSPaintFilterCanvas>(recordingCanvas_.get());
329             ProcessCPURenderInBackgroundThread(cmds, context, nodeId);
330         }
331     }
332 }
333 
Flush(float width,float height,std::shared_ptr<RSContext> context,NodeId nodeId,RSPaintFilterCanvas & rscanvas)334 void RSCanvasDrawingRenderNodeDrawable::Flush(float width, float height, std::shared_ptr<RSContext> context,
335     NodeId nodeId, RSPaintFilterCanvas& rscanvas)
336 {
337 #if defined(RS_ENABLE_GL) || defined(RS_ENABLE_VK)
338     if (RSSystemProperties::GetGpuApiType() == GpuApiType::VULKAN ||
339         RSSystemProperties::GetGpuApiType() == GpuApiType::DDGR) {
340         FlushForVK(width, height, context, nodeId, rscanvas);
341     }
342     if (RSSystemProperties::GetGpuApiType() == GpuApiType::OPENGL) {
343         FlushForGL(width, height, context, nodeId, rscanvas);
344     }
345 #endif
346 }
347 
ProcessCPURenderInBackgroundThread(std::shared_ptr<Drawing::DrawCmdList> cmds,std::shared_ptr<RSContext> ctx,NodeId nodeId)348 void RSCanvasDrawingRenderNodeDrawable::ProcessCPURenderInBackgroundThread(std::shared_ptr<Drawing::DrawCmdList> cmds,
349     std::shared_ptr<RSContext> ctx, NodeId nodeId)
350 {
351     auto surface = surface_;
352     auto drawable = RSRenderNodeDrawableAdapter::GetDrawableById(nodeId);
353     RSBackgroundThread::Instance().PostTask([drawable, cmds, surface, ctx, nodeId]() {
354         if (!cmds || cmds->IsEmpty() || !surface || !ctx || !drawable) {
355             return;
356         }
357         auto canvasDrawingDrawable = std::static_pointer_cast<DrawableV2::RSCanvasDrawingRenderNodeDrawable>(drawable);
358         {
359             std::unique_lock<std::recursive_mutex> lock(canvasDrawingDrawable->drawableMutex_);
360             if (surface != canvasDrawingDrawable->surface_) {
361                 return;
362             }
363             cmds->Playback(*surface->GetCanvas());
364             auto image = surface->GetImageSnapshot(); // planning: adapt multithread
365             if (image) {
366                 SKResourceManager::Instance().HoldResource(image);
367             }
368             canvasDrawingDrawable->image_ = image;
369         }
370         if (UNLIKELY(!ctx)) {
371             return;
372         }
373         RSMainThread::Instance()->PostTask([ctx, nodeId]() {
374             if (auto node = ctx->GetNodeMap().GetRenderNode<RSCanvasDrawingRenderNode>(nodeId)) {
375                 ROSEN_LOGD("Node id %{public}" PRIu64 " set dirty, process in RSMainThread", nodeId);
376                 node->SetDirty();
377                 ctx->RequestVsync();
378             }
379         });
380     });
381 }
382 
ResetSurface()383 void RSCanvasDrawingRenderNodeDrawable::ResetSurface()
384 {
385     if (surface_ && surface_->GetImageInfo().GetWidth() > EDGE_WIDTH_LIMIT) {
386         RS_LOGI("RSCanvasDrawingRenderNodeDrawable::ResetSurface id:%{public}" PRIu64 "", nodeId_);
387     }
388     if (preThreadInfo_.second && surface_) {
389         preThreadInfo_.second(std::move(surface_));
390     }
391     surface_ = nullptr;
392     recordingCanvas_ = nullptr;
393     image_ = nullptr;
394     canvas_ = nullptr;
395 #if (defined(RS_ENABLE_GL) || defined(RS_ENABLE_VK))
396     backendTexture_ = {};
397     if (RSSystemProperties::GetGpuApiType() == GpuApiType::VULKAN ||
398         RSSystemProperties::GetGpuApiType() == GpuApiType::DDGR) {
399 #ifdef RS_ENABLE_VK
400         if (vulkanCleanupHelper_ && isPurge_) {
401             vulkanCleanupHelper_->UnRef();
402             isPurge_ = false;
403         }
404 #endif
405         vulkanCleanupHelper_ = nullptr;
406     }
407 #endif
408 }
409 
410 // use in IPC thread
GetBitmap(Drawing::GPUContext * grContext)411 Drawing::Bitmap RSCanvasDrawingRenderNodeDrawable::GetBitmap(Drawing::GPUContext* grContext)
412 {
413     Drawing::Bitmap bitmap;
414     std::unique_lock<std::recursive_mutex> lock(drawableMutex_);
415     // Judge valid of backendTexture_ by checking the image_.
416     if (!image_) {
417         RS_LOGE("Failed to get bitmap, image is null!");
418         return bitmap;
419     }
420     if (!grContext) {
421         RS_LOGE("Failed to get bitmap, grContext is null!");
422         return bitmap;
423     }
424 #if (defined(RS_ENABLE_GL) || defined(RS_ENABLE_VK))
425     Drawing::TextureOrigin origin = GetTextureOrigin();
426     Drawing::BitmapFormat info = Drawing::BitmapFormat{ image_->GetColorType(), image_->GetAlphaType() };
427     auto image = std::make_shared<Drawing::Image>();
428     bool ret = image->BuildFromTexture(*grContext, backendTexture_.GetTextureInfo(), origin, info, nullptr);
429     if (!ret) {
430         RS_LOGE("RSCanvasDrawingRenderNodeDrawable::GetBitmap image BuildFromTexture failed");
431         return bitmap;
432     }
433     if (!image->AsLegacyBitmap(bitmap)) {
434         RS_LOGE("Failed to get bitmap, asLegacyBitmap failed");
435     }
436 #endif
437     return bitmap;
438 }
439 
WriteSkImageToPixelmap(std::shared_ptr<Drawing::Image> image,Drawing::ImageInfo info,std::shared_ptr<Media::PixelMap> pixelmap,const Drawing::Rect * rect)440 static bool WriteSkImageToPixelmap(std::shared_ptr<Drawing::Image> image, Drawing::ImageInfo info,
441     std::shared_ptr<Media::PixelMap> pixelmap, const Drawing::Rect* rect)
442 {
443     if (image == nullptr || pixelmap == nullptr || rect == nullptr) {
444         return false;
445     }
446     return image->ReadPixels(
447         info, pixelmap->GetWritablePixels(), pixelmap->GetRowStride(),
448         rect->GetLeft(), rect->GetTop());
449 }
450 
451 // use in IPC thread
GetPixelmap(const std::shared_ptr<Media::PixelMap> pixelmap,const Drawing::Rect * rect,const uint64_t tid,std::shared_ptr<Drawing::DrawCmdList> drawCmdList)452 bool RSCanvasDrawingRenderNodeDrawable::GetPixelmap(const std::shared_ptr<Media::PixelMap> pixelmap,
453     const Drawing::Rect* rect, const uint64_t tid, std::shared_ptr<Drawing::DrawCmdList> drawCmdList)
454 {
455     std::unique_lock<std::recursive_mutex> lock(drawableMutex_);
456 
457     if (!pixelmap || !rect) {
458         RS_LOGE("RSCanvasDrawingRenderNodeDrawable::GetPixelmap: pixelmap is nullptr");
459         return false;
460     }
461     if (!canvas_ || !image_ || !surface_) {
462         RS_LOGE("RSCanvasDrawingRenderNodeDrawable::GetPixelmap: canvas/image/surface is nullptr");
463         return false;
464     }
465     std::shared_ptr<Drawing::Image> image;
466     std::shared_ptr<Drawing::GPUContext> grContext;
467     if (!GetCurrentContextAndImage(grContext, image, tid)) {
468         RS_LOGE("RSCanvasDrawingRenderNodeDrawable::GetPixelmap: GetCurrentContextAndImage failed");
469         return false;
470     }
471 
472     if (image == nullptr) {
473         RS_LOGE("RSCanvasDrawingRenderNodeDrawable::GetPixelmap: image is nullptr");
474         return false;
475     }
476 
477     Drawing::ImageInfo info = Drawing::ImageInfo { pixelmap->GetWidth(), pixelmap->GetHeight(),
478         Drawing::COLORTYPE_RGBA_8888, Drawing::ALPHATYPE_PREMUL };
479     if (!drawCmdList) {
480         if (!WriteSkImageToPixelmap(image, info, pixelmap, rect)) {
481             RS_LOGE("RSCanvasDrawingRenderNodeDrawable::GetPixelmap: readPixels failed");
482             return false;
483         }
484         return true;
485     }
486     std::shared_ptr<Drawing::Surface> surface;
487     std::unique_ptr<RSPaintFilterCanvas> canvas;
488 #if (defined(RS_ENABLE_GL) || defined(RS_ENABLE_VK))
489     if (grContext == nullptr) {
490         if (!WriteSkImageToPixelmap(image, info, pixelmap, rect)) {
491             RS_LOGE("RSCanvasDrawingRenderNodeDrawable::GetPixelmap: readPixels failed");
492         }
493         return false;
494     } else {
495         Drawing::ImageInfo newInfo = Drawing::ImageInfo{ image->GetWidth(), image->GetHeight(),
496             Drawing::COLORTYPE_RGBA_8888, Drawing::ALPHATYPE_PREMUL };
497         surface = Drawing::Surface::MakeRenderTarget(grContext.get(), false, newInfo);
498         if (!surface) {
499             if (!WriteSkImageToPixelmap(image, info, pixelmap, rect)) {
500                 RS_LOGE("RSCanvasDrawingRenderNodeDrawable::GetPixelmap: readPixels failed");
501             }
502             return false;
503         }
504         canvas = std::make_unique<RSPaintFilterCanvas>(surface.get());
505     }
506 #else
507     if (!WriteSkImageToPixelmap(image, info, pixelmap, rect)) {
508         RS_LOGE("RSCanvasDrawingRenderNodeDrawable::GetPixelmap: readPixels failed");
509     }
510     return false;
511 #endif
512     canvas->DrawImage(*image, 0, 0, Drawing::SamplingOptions());
513     drawCmdList->Playback(*canvas, rect);
514     auto pixelmapImage = surface->GetImageSnapshot();
515     if (!WriteSkImageToPixelmap(pixelmapImage, info, pixelmap, rect)) {
516         RS_LOGE("RSCanvasDrawingRenderNodeDrawable::GetPixelmap: readPixels failed");
517         return false;
518     }
519     return true;
520 }
521 
IsNeedResetSurface() const522 bool RSCanvasDrawingRenderNodeDrawable::IsNeedResetSurface() const
523 {
524     return !surface_ || !surface_->GetCanvas();
525 }
526 
ReleaseCaptureImage()527 void RSCanvasDrawingRenderNodeDrawable::ReleaseCaptureImage()
528 {
529     RSOffscreenRenderThread::Instance().PostTask([image = captureImage_]() mutable { image = nullptr; });
530     captureImage_ = nullptr;
531 }
532 
DrawCaptureImage(RSPaintFilterCanvas & canvas)533 void RSCanvasDrawingRenderNodeDrawable::DrawCaptureImage(RSPaintFilterCanvas& canvas)
534 {
535 #if (defined(RS_ENABLE_GL) || defined(RS_ENABLE_VK))
536     if (!image_) {
537         OnDraw(canvas);
538         return;
539     }
540     if (image_ && !image_->IsTextureBacked()) {
541         canvas.DrawImage(*image_, 0, 0, Drawing::SamplingOptions());
542         return;
543     }
544 
545     if (RSSystemProperties::GetGpuApiType() == GpuApiType::OPENGL) {
546         return;
547     }
548 
549     if (!backendTexture_.IsValid()) {
550         return;
551     }
552     if (canvas.GetGPUContext() == nullptr) {
553         RS_LOGE("RSCanvasDrawingRenderNodeDrawable::DrawCaptureImage canvas.GetGPUContext is nullptr");
554         return;
555     }
556     if (captureImage_ && captureImage_->IsValid(canvas.GetGPUContext().get())) {
557         canvas.DrawImage(*captureImage_, 0, 0, Drawing::SamplingOptions());
558         return;
559     }
560     Drawing::TextureOrigin origin = GetTextureOrigin();
561     Drawing::BitmapFormat info = Drawing::BitmapFormat{ image_->GetColorType(), image_->GetAlphaType() };
562     SharedTextureContext* sharedContext = new SharedTextureContext(image_);
563     captureImage_ = std::make_shared<Drawing::Image>();
564     bool ret = captureImage_->BuildFromTexture(*canvas.GetGPUContext(), backendTexture_.GetTextureInfo(), origin, info,
565         nullptr, SKResourceManager::DeleteSharedTextureContext, sharedContext);
566     if (!ret) {
567         RS_LOGE("RSCanvasDrawingRenderNodeDrawable::DrawCaptureImage BuildFromTexture failed");
568         return;
569     }
570     canvas.DrawImage(*captureImage_, 0, 0, Drawing::SamplingOptions());
571 #endif
572 }
573 
ResetSurfaceForVK(int width,int height,RSPaintFilterCanvas & canvas)574 bool RSCanvasDrawingRenderNodeDrawable::ResetSurfaceForVK(int width, int height, RSPaintFilterCanvas& canvas)
575 {
576     Drawing::ImageInfo info =
577         Drawing::ImageInfo { width, height, Drawing::COLORTYPE_RGBA_8888, Drawing::ALPHATYPE_PREMUL };
578 
579     bool isNewCreate = false;
580 #ifdef RS_ENABLE_VK
581     auto gpuContext = canvas.GetRecordingState() ? nullptr : canvas.GetGPUContext();
582     isGpuSurface_ = true;
583     if (gpuContext == nullptr) {
584         RS_LOGE("RSCanvasDrawingRenderNodeDrawable::ResetSurface: gpuContext is nullptr");
585         isGpuSurface_ = false;
586         surface_ = Drawing::Surface::MakeRaster(info);
587     } else {
588         if (!backendTexture_.IsValid() || !backendTexture_.GetTextureInfo().GetVKTextureInfo()) {
589             backendTexture_ = RSUniRenderUtil::MakeBackendTexture(width, height);
590             if (!backendTexture_.IsValid()) {
591                 surface_ = nullptr;
592                 recordingCanvas_ = nullptr;
593                 image_ = nullptr;
594                 canvas_ = nullptr;
595                 backendTexture_ = {};
596                 if (RSSystemProperties::GetGpuApiType() == GpuApiType::VULKAN ||
597                     RSSystemProperties::GetGpuApiType() == GpuApiType::DDGR) {
598                     if (vulkanCleanupHelper_ && isPurge_) {
599                         vulkanCleanupHelper_->UnRef();
600                         isPurge_ = false;
601                     }
602                     vulkanCleanupHelper_ = nullptr;
603                 }
604                 RS_LOGE(
605                     "RSCanvasDrawingRenderNodeDrawable::ResetSurfaceForVK size too big [%{public}d, %{public}d] failed",
606                     width, height);
607                 return false;
608             }
609         }
610         auto vkTextureInfo = backendTexture_.GetTextureInfo().GetVKTextureInfo();
611         if (vulkanCleanupHelper_ == nullptr) {
612             vulkanCleanupHelper_ = new NativeBufferUtils::VulkanCleanupHelper(
613             RsVulkanContext::GetSingleton(), vkTextureInfo->vkImage, vkTextureInfo->vkAlloc.memory);
614             isNewCreate = true;
615         }
616         REAL_ALLOC_CONFIG_SET_STATUS(true);
617         surface_ = Drawing::Surface::MakeFromBackendTexture(gpuContext.get(), backendTexture_.GetTextureInfo(),
618             Drawing::TextureOrigin::TOP_LEFT, 1, Drawing::ColorType::COLORTYPE_RGBA_8888, nullptr,
619             NativeBufferUtils::DeleteVkImage, isNewCreate ? vulkanCleanupHelper_ : vulkanCleanupHelper_->Ref());
620         REAL_ALLOC_CONFIG_SET_STATUS(false);
621         if (!surface_) {
622             isGpuSurface_ = false;
623             surface_ = Drawing::Surface::MakeRaster(info);
624             if (!surface_) {
625                 RS_LOGE("RSCanvasDrawingRenderNodeDrawable::ResetSurface surface is nullptr");
626                 return false;
627             }
628             recordingCanvas_ = std::make_shared<ExtendRecordingCanvas>(width, height, false);
629             canvas_ = std::make_unique<RSPaintFilterCanvas>(recordingCanvas_.get());
630             return true;
631         }
632     }
633 #else
634     surface_ = Drawing::Surface::MakeRaster(info);
635 #endif
636     if (!surface_) {
637         RS_LOGE("RSCanvasDrawingRenderNodeDrawable::ResetSurface surface is nullptr");
638         return false;
639     }
640     recordingCanvas_ = nullptr;
641     canvas_ = std::make_shared<RSPaintFilterCanvas>(surface_.get());
642     if (isNewCreate) {
643         canvas_->Clear(Drawing::Color::COLOR_TRANSPARENT);
644     }
645     return true;
646 }
647 
ResetSurfaceForGL(int width,int height,RSPaintFilterCanvas & canvas)648 bool RSCanvasDrawingRenderNodeDrawable::ResetSurfaceForGL(int width, int height, RSPaintFilterCanvas& canvas)
649 {
650     Drawing::ImageInfo info =
651         Drawing::ImageInfo { width, height, Drawing::COLORTYPE_RGBA_8888, Drawing::ALPHATYPE_PREMUL };
652 
653 #if (defined(RS_ENABLE_GL) || defined(RS_ENABLE_VK))
654     auto gpuContext = canvas.GetRecordingState() ? nullptr : canvas.GetGPUContext();
655     isGpuSurface_ = true;
656     if (gpuContext == nullptr) {
657         RS_LOGE("RSCanvasDrawingRenderNodeDrawable::ResetSurface: gpuContext is nullptr");
658         isGpuSurface_ = false;
659         surface_ = Drawing::Surface::MakeRaster(info);
660     } else {
661         surface_ = Drawing::Surface::MakeRenderTarget(gpuContext.get(), false, info);
662         if (!surface_) {
663             isGpuSurface_ = false;
664             surface_ = Drawing::Surface::MakeRaster(info);
665             if (!surface_) {
666                 RS_LOGE("RSCanvasDrawingRenderNodeDrawable::ResetSurface surface is nullptr");
667                 return false;
668             }
669             recordingCanvas_ = std::make_shared<ExtendRecordingCanvas>(width, height, false);
670             canvas_ = std::make_unique<RSPaintFilterCanvas>(recordingCanvas_.get());
671             return true;
672         }
673     }
674 #else
675     surface_ = Drawing::Surface::MakeRaster(info);
676 #endif
677     if (!surface_) {
678         RS_LOGE("RSCanvasDrawingRenderNodeDrawable::ResetSurface surface is nullptr");
679         return false;
680     }
681     recordingCanvas_ = nullptr;
682     canvas_ = std::make_shared<RSPaintFilterCanvas>(surface_.get());
683     return true;
684 }
685 
686 #if (defined(RS_ENABLE_GL) || defined(RS_ENABLE_VK))
ClearPreSurface(std::shared_ptr<Drawing::Surface> & preSurface)687 inline void RSCanvasDrawingRenderNodeDrawable::ClearPreSurface(std::shared_ptr<Drawing::Surface>& preSurface)
688 {
689     if (preThreadInfo_.second && preSurface) {
690         preThreadInfo_.second(std::move(preSurface));
691     }
692 }
693 
ReuseBackendTexture(int width,int height,RSPaintFilterCanvas & canvas)694 bool RSCanvasDrawingRenderNodeDrawable::ReuseBackendTexture(int width, int height, RSPaintFilterCanvas& canvas)
695 {
696     auto preMatrix = canvas_->GetTotalMatrix();
697     auto preDeviceClipBounds = canvas_->GetDeviceClipBounds();
698     auto preSaveCount = canvas_->GetSaveCount();
699     auto preSurface = surface_;
700     if (!ResetSurfaceForVK(width, height, canvas)) {
701         ClearPreSurface(preSurface);
702         return false;
703     }
704     if (preSaveCount > 1) {
705         canvas_->Save();
706     }
707     canvas_->ClipIRect(preDeviceClipBounds);
708     canvas_->SetMatrix(preMatrix);
709     ClearPreSurface(preSurface);
710     preThreadInfo_ = curThreadInfo_;
711     ReleaseCaptureImage();
712     return true;
713 }
714 
GetCurrentContextAndImage(std::shared_ptr<Drawing::GPUContext> & grContext,std::shared_ptr<Drawing::Image> & image,const uint64_t tid)715 bool RSCanvasDrawingRenderNodeDrawable::GetCurrentContextAndImage(std::shared_ptr<Drawing::GPUContext>& grContext,
716     std::shared_ptr<Drawing::Image>& image, const uint64_t tid)
717 {
718     if (tid == preThreadInfo_.first) {
719         grContext = canvas_->GetGPUContext();
720         image = image_;
721     } else {
722         auto realTid = gettid();
723         if (realTid == RSUniRenderThread::Instance().GetTid()) {
724             grContext = RSUniRenderThread::Instance().GetRenderEngine()->GetRenderContext()->GetSharedDrGPUContext();
725         } else {
726             if (!RSSubThreadManager::Instance()->GetGrContextFromSubThread(realTid)) {
727                 RS_LOGE("RSCanvasDrawingRenderNodeDrawable::GetCurrentContextAndImage get grGrContext failed");
728                 return false;
729             }
730             grContext = RSSubThreadManager::Instance()->GetGrContextFromSubThread(realTid);
731         }
732 
733         if (!grContext || !backendTexture_.IsValid()) {
734             return false;
735         }
736         Drawing::TextureOrigin origin = GetTextureOrigin();
737         Drawing::BitmapFormat info = Drawing::BitmapFormat{ image_->GetColorType(), image_->GetAlphaType() };
738         image = std::make_shared<Drawing::Image>();
739         bool ret = image->BuildFromTexture(*grContext, backendTexture_.GetTextureInfo(), origin, info, nullptr);
740         if (!ret) {
741             RS_LOGE("RSCanvasDrawingRenderNodeDrawable::GetCurrentContextAndImage BuildFromTexture failed");
742             return false;
743         }
744     }
745     return true;
746 }
747 
ResetSurfaceWithTexture(int width,int height,RSPaintFilterCanvas & canvas)748 bool RSCanvasDrawingRenderNodeDrawable::ResetSurfaceWithTexture(int width, int height, RSPaintFilterCanvas& canvas)
749 {
750     if (width > EDGE_WIDTH_LIMIT) {
751         RS_LOGI("RSCanvasDrawingRenderNodeDrawable::ResetSurfaceWithTexture id:%{public}" PRIu64 " "
752              "width:%{public}d height:%{public}d ", nodeId_, width, height);
753     }
754     auto preMatrix = canvas_->GetTotalMatrix();
755     auto preDeviceClipBounds = canvas_->GetDeviceClipBounds();
756     auto preSaveCount = canvas_->GetSaveCount();
757     auto preSurface = surface_;
758     if (!ResetSurfaceForGL(width, height, canvas)) {
759         ClearPreSurface(preSurface);
760         return false;
761     }
762     if (!backendTexture_.IsValid()) {
763         RS_LOGE("RSCanvasDrawingRenderNodeDrawable::ResetSurfaceWithTexture backendTexture_ is nullptr");
764         ClearPreSurface(preSurface);
765         return false;
766     }
767     if (canvas.GetGPUContext() == nullptr) {
768         RS_LOGE("RSCanvasDrawingRenderNodeDrawable::ResetSurfaceWithTexture GPU context is nullptr");
769         ClearPreSurface(preSurface);
770         return false;
771     }
772 
773     Drawing::TextureOrigin origin = GetTextureOrigin();
774     Drawing::BitmapFormat bitmapFormat = { image_->GetColorType(), image_->GetAlphaType() };
775     SharedTextureContext* sharedContext = new SharedTextureContext(image_); // will move image
776     auto preImageInNewContext = std::make_shared<Drawing::Image>();
777     if (!preImageInNewContext->BuildFromTexture(*canvas.GetGPUContext(), backendTexture_.GetTextureInfo(),
778         origin, bitmapFormat, nullptr, SKResourceManager::DeleteSharedTextureContext, sharedContext)) {
779         RS_LOGE("RSCanvasDrawingRenderNodeDrawable::ResetSurfaceWithTexture preImageInNewContext is nullptr");
780         ClearPreSurface(preSurface);
781         return false;
782     }
783     if (RSSystemProperties::GetRecordingEnabled()) {
784         if (preImageInNewContext->IsTextureBacked()) {
785             RS_LOGI("RSCanvasDrawingRenderNodeDrawable::ResetSurfaceWithTexture preImageInNewContext "
786                 "from texture to raster image");
787             preImageInNewContext = preImageInNewContext->MakeRasterImage();
788         }
789     }
790     canvas_->DrawImage(*preImageInNewContext, 0.f, 0.f, Drawing::SamplingOptions());
791     if (preSaveCount > 1) {
792         canvas_->Save();
793     }
794     canvas_->ClipIRect(preDeviceClipBounds);
795     canvas_->SetMatrix(preMatrix);
796     canvas_->Flush();
797     backendTexture_ = surface_->GetBackendTexture();
798     if (!backendTexture_.IsValid()) {
799         RS_LOGE("RSCanvasDrawingRenderNodeDrawable::ResetSurfaceWithTexture backendTexture_ generate invalid");
800     }
801     image_ = preImageInNewContext;
802     ReleaseCaptureImage();
803     ClearPreSurface(preSurface);
804     preThreadInfo_ = curThreadInfo_;
805     return true;
806 }
807 #endif
808 
GetTextureOrigin()809 Drawing::TextureOrigin RSCanvasDrawingRenderNodeDrawable::GetTextureOrigin()
810 {
811     if (RSSystemProperties::GetGpuApiType() == GpuApiType::OPENGL) {
812         return Drawing::TextureOrigin::BOTTOM_LEFT;
813     }
814     return Drawing::TextureOrigin::TOP_LEFT;
815 }
816 
DrawRegionForDfx(Drawing::Canvas & canvas,const Drawing::Rect & bounds)817 void RSCanvasDrawingRenderNodeDrawable::DrawRegionForDfx(Drawing::Canvas& canvas, const Drawing::Rect& bounds)
818 {
819     if (!RSSystemParameters::GetCanvasDrawingNodeRegionEnabled()) {
820         return;
821     }
822     Drawing::Pen pen;
823     pen.SetWidth(DRAW_REGION_FOR_DFX_BORDER);
824     pen.SetColor(Drawing::Color::COLOR_RED);
825     canvas.AttachPen(pen);
826     canvas.DrawRect(Drawing::Rect(0, 0, bounds.GetWidth(), bounds.GetHeight()));
827     canvas.DetachPen();
828 }
829 
830 } // namespace OHOS::Rosen::DrawableV2
831