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