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