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