1 /*
2 * Copyright (c) 2021-2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "pipeline/rs_render_thread_visitor.h"
17
18 #include <cmath>
19 #include <include/core/SkColor.h>
20 #include <include/core/SkFont.h>
21 #include <include/core/SkMatrix.h>
22 #include <include/core/SkPaint.h>
23 #include <include/core/SkRect.h>
24
25 #include "rs_trace.h"
26
27 #include "command/rs_base_node_command.h"
28 #include "common/rs_vector4.h"
29 #include "pipeline/rs_canvas_render_node.h"
30 #include "pipeline/rs_dirty_region_manager.h"
31 #include "pipeline/rs_node_map.h"
32 #include "pipeline/rs_proxy_render_node.h"
33 #include "pipeline/rs_render_thread.h"
34 #include "pipeline/rs_root_render_node.h"
35 #include "pipeline/rs_surface_render_node.h"
36 #include "platform/common/rs_log.h"
37 #include "platform/drawing/rs_surface.h"
38 #include "transaction/rs_transaction_proxy.h"
39 #include "ui/rs_surface_extractor.h"
40 #include "ui/rs_surface_node.h"
41
42 #ifdef ROSEN_OHOS
43 #include <frame_collector.h>
44 #include <frame_painter.h>
45 #include "platform/ohos/overdraw/rs_cpu_overdraw_canvas_listener.h"
46 #include "platform/ohos/overdraw/rs_gpu_overdraw_canvas_listener.h"
47 #include "platform/ohos/overdraw/rs_overdraw_controller.h"
48 #endif
49
50 namespace OHOS {
51 namespace Rosen {
RSRenderThreadVisitor()52 RSRenderThreadVisitor::RSRenderThreadVisitor()
53 : curDirtyManager_(std::make_shared<RSDirtyRegionManager>()), canvas_(nullptr) {}
54
55 RSRenderThreadVisitor::~RSRenderThreadVisitor() = default;
56
IsValidRootRenderNode(RSRootRenderNode & node)57 bool RSRenderThreadVisitor::IsValidRootRenderNode(RSRootRenderNode& node)
58 {
59 auto ptr = RSNodeMap::Instance().GetNode<RSSurfaceNode>(node.GetRSSurfaceNodeId());
60 if (ptr == nullptr) {
61 ROSEN_LOGE("No valid RSSurfaceNode id");
62 return false;
63 }
64 if (!node.enableRender_) {
65 ROSEN_LOGD("RootNode %s: Invisible", ptr->GetName().c_str());
66 return false;
67 }
68 if (node.GetSuggestedBufferWidth() <= 0 || node.GetSuggestedBufferHeight() <= 0) {
69 ROSEN_LOGD("Root %s: Negative width or height [%f %f]", ptr->GetName().c_str(),
70 node.GetSuggestedBufferWidth(), node.GetSuggestedBufferHeight());
71 return false;
72 }
73 return true;
74 }
75
SetPartialRenderStatus(PartialRenderType status,bool isRenderForced)76 void RSRenderThreadVisitor::SetPartialRenderStatus(PartialRenderType status, bool isRenderForced)
77 {
78 isRenderForced_ = isRenderForced;
79 isEglSetDamageRegion_ = !isRenderForced_ && (status != PartialRenderType::DISABLED);
80 isOpDropped_ = !isRenderForced_ && (status == PartialRenderType::SET_DAMAGE_AND_DROP_OP);
81 if (partialRenderStatus_ == status) {
82 ROSEN_LOGD("SetPartialRenderStatus: %d->%d, isRenderForced_=%d, isEglSetDamageRegion_=%d, isOpDropped_=%d",
83 partialRenderStatus_, status, isRenderForced_, isEglSetDamageRegion_, isOpDropped_);
84 }
85 partialRenderStatus_ = status;
86 }
87
PrepareBaseRenderNode(RSBaseRenderNode & node)88 void RSRenderThreadVisitor::PrepareBaseRenderNode(RSBaseRenderNode& node)
89 {
90 node.ResetSortedChildren();
91 for (auto& child : node.GetChildren()) {
92 if (auto renderChild = RSBaseRenderNode::ReinterpretCast<RSRenderNode>(child.lock())) {
93 renderChild->ApplyModifiers();
94 }
95 }
96 for (auto& child : node.GetSortedChildren()) {
97 child->Prepare(shared_from_this());
98 }
99 }
100
PrepareRootRenderNode(RSRootRenderNode & node)101 void RSRenderThreadVisitor::PrepareRootRenderNode(RSRootRenderNode& node)
102 {
103 if (isIdle_) {
104 curDirtyManager_ = node.GetDirtyManager();
105 curDirtyManager_->Clear();
106 // After the node calls ApplyModifiers, the modifiers assign the renderProperties to the node
107 // Otherwise node.GetSuggestedBufferHeight always less than 0, causing black screen
108 node.ApplyModifiers();
109 if (!IsValidRootRenderNode(node)) {
110 return;
111 }
112 dirtyFlag_ = false;
113 isIdle_ = false;
114 PrepareCanvasRenderNode(node);
115 isIdle_ = true;
116 } else {
117 PrepareCanvasRenderNode(node);
118 }
119 }
120
PrepareCanvasRenderNode(RSCanvasRenderNode & node)121 void RSRenderThreadVisitor::PrepareCanvasRenderNode(RSCanvasRenderNode& node)
122 {
123 node.ApplyModifiers();
124 if (!node.ShouldPaint()) {
125 return;
126 }
127 bool dirtyFlag = dirtyFlag_;
128 auto nodeParent = node.GetParent().lock();
129 std::shared_ptr<RSRenderNode> rsParent = nullptr;
130 if (nodeParent != nullptr) {
131 rsParent = nodeParent->ReinterpretCastTo<RSRenderNode>();
132 }
133 dirtyFlag_ = node.Update(*curDirtyManager_, rsParent ? &(rsParent->GetRenderProperties()) : nullptr, dirtyFlag_);
134 if (node.IsDirtyRegionUpdated() && curDirtyManager_->IsDebugRegionTypeEnable(DebugRegionType::CURRENT_SUB)) {
135 curDirtyManager_->UpdateDirtyCanvasNodes(node.GetId(), node.GetOldDirty());
136 }
137 PrepareBaseRenderNode(node);
138 dirtyFlag_ = dirtyFlag;
139 }
140
PrepareSurfaceRenderNode(RSSurfaceRenderNode & node)141 void RSRenderThreadVisitor::PrepareSurfaceRenderNode(RSSurfaceRenderNode& node)
142 {
143 node.ApplyModifiers();
144 bool dirtyFlag = dirtyFlag_;
145 auto nodeParent = node.GetParent().lock();
146 std::shared_ptr<RSRenderNode> rsParent = nullptr;
147 if (nodeParent != nullptr) {
148 rsParent = nodeParent->ReinterpretCastTo<RSRenderNode>();
149 }
150 // If rt buffer switches to be available
151 // set its SurfaceRenderNode's render dirty
152 if (!node.IsNotifyRTBufferAvailablePre() && node.IsNotifyRTBufferAvailable()) {
153 ROSEN_LOGD("NotifyRTBufferAvailable and set it dirty");
154 node.SetDirty();
155 }
156 dirtyFlag_ = node.Update(*curDirtyManager_, rsParent ? &(rsParent->GetRenderProperties()) : nullptr, dirtyFlag_);
157 if (node.IsDirtyRegionUpdated() && curDirtyManager_->IsDebugRegionTypeEnable(DebugRegionType::CURRENT_SUB)) {
158 curDirtyManager_->UpdateDirtySurfaceNodes(node.GetId(), node.GetOldDirty());
159 }
160 PrepareBaseRenderNode(node);
161 dirtyFlag_ = dirtyFlag;
162 }
163
DrawRectOnCanvas(const RectI & dirtyRect,const SkColor color,const SkPaint::Style fillType,float alpha)164 void RSRenderThreadVisitor::DrawRectOnCanvas(const RectI& dirtyRect, const SkColor color,
165 const SkPaint::Style fillType, float alpha)
166 {
167 if (dirtyRect.width_ <= 0 || dirtyRect.height_ <= 0) {
168 ROSEN_LOGD("DrawRectOnCanvas dirty rect is invalid.");
169 return;
170 }
171 auto skRect = SkRect::MakeXYWH(dirtyRect.left_, dirtyRect.top_, dirtyRect.width_, dirtyRect.height_);
172 const int defaultEdgeWidth = 6;
173 SkPaint rectPaint;
174 rectPaint.setColor(color);
175 rectPaint.setAntiAlias(true);
176 rectPaint.setAlphaf(alpha);
177 rectPaint.setStyle(fillType);
178 rectPaint.setStrokeWidth(defaultEdgeWidth);
179 if (fillType == SkPaint::kFill_Style) {
180 rectPaint.setStrokeJoin(SkPaint::kRound_Join);
181 }
182 canvas_->drawRect(skRect, rectPaint);
183 }
184
DrawDirtyRegion()185 void RSRenderThreadVisitor::DrawDirtyRegion()
186 {
187 auto dirtyRect = RectI();
188 const float fillAlpha = 0.2;
189 const float edgeAlpha = 0.4;
190 const float subFactor = 2.0;
191
192 if (curDirtyManager_->IsDebugRegionTypeEnable(DebugRegionType::MULTI_HISTORY)) {
193 dirtyRect = curDirtyManager_->GetDirtyRegion();
194 if (dirtyRect.IsEmpty()) {
195 ROSEN_LOGD("DrawDirtyRegion his dirty rect is invalid. dirtyRect = [%d, %d, %d, %d]",
196 dirtyRect.left_, dirtyRect.top_, dirtyRect.width_, dirtyRect.height_);
197 } else {
198 ROSEN_LOGD("DrawDirtyRegion his dirty rect. dirtyRect = [%d, %d, %d, %d]",
199 dirtyRect.left_, dirtyRect.top_, dirtyRect.width_, dirtyRect.height_);
200 // green
201 DrawRectOnCanvas(dirtyRect, 0xFF0AFF0A, SkPaint::kFill_Style, fillAlpha / subFactor);
202 DrawRectOnCanvas(dirtyRect, 0xFF0AFF0A, SkPaint::kStroke_Style, edgeAlpha);
203 }
204 }
205
206 if (curDirtyManager_->IsDebugRegionTypeEnable(DebugRegionType::CURRENT_WHOLE)) {
207 dirtyRect = curDirtyManager_->GetLatestDirtyRegion();
208 if (dirtyRect.IsEmpty()) {
209 ROSEN_LOGD("DrawDirtyRegion current frame's dirty rect is invalid. dirtyRect = [%d, %d, %d, %d]",
210 dirtyRect.left_, dirtyRect.top_, dirtyRect.width_, dirtyRect.height_);
211 } else {
212 ROSEN_LOGD("DrawDirtyRegion cur dirty rect. dirtyRect = [%d, %d, %d, %d]",
213 dirtyRect.left_, dirtyRect.top_, dirtyRect.width_, dirtyRect.height_);
214 // yellow
215 DrawRectOnCanvas(dirtyRect, 0xFFFFFF00, SkPaint::kFill_Style, fillAlpha);
216 DrawRectOnCanvas(dirtyRect, 0xFFFFFF00, SkPaint::kStroke_Style, edgeAlpha);
217 }
218 }
219
220 if (curDirtyManager_->IsDebugRegionTypeEnable(DebugRegionType::CURRENT_SUB)) {
221 std::map<NodeId, RectI> dirtySubRects_;
222 curDirtyManager_->GetDirtyCanvasNodes(dirtySubRects_);
223 for (const auto& [nid, subRect] : dirtySubRects_) {
224 ROSEN_LOGD("DrawDirtyRegion canvasNode id %" PRIu64 " is dirty. dirtyRect = [%d, %d, %d, %d]", nid,
225 subRect.left_, subRect.top_, subRect.width_, subRect.height_);
226 // red
227 DrawRectOnCanvas(subRect, 0xFFFF0000, SkPaint::kStroke_Style, edgeAlpha / subFactor);
228 }
229
230 curDirtyManager_->GetDirtySurfaceNodes(dirtySubRects_);
231 for (const auto& [nid, subRect] : dirtySubRects_) {
232 ROSEN_LOGD("DrawDirtyRegion surfaceNode id %" PRIu64 " is dirty. dirtyRect = [%d, %d, %d, %d]", nid,
233 subRect.left_, subRect.top_, subRect.width_, subRect.height_);
234 // light purple
235 DrawRectOnCanvas(subRect, 0xFFD899D8, SkPaint::kStroke_Style, edgeAlpha);
236 }
237 }
238 }
239
UpdateDirtyAndSetEGLDamageRegion(std::unique_ptr<RSSurfaceFrame> & surfaceFrame)240 void RSRenderThreadVisitor::UpdateDirtyAndSetEGLDamageRegion(std::unique_ptr<RSSurfaceFrame>& surfaceFrame)
241 {
242 RS_TRACE_BEGIN("UpdateDirtyAndSetEGLDamageRegion");
243 #ifdef RS_ENABLE_EGLQUERYSURFACE
244 if (isEglSetDamageRegion_) {
245 // get and update valid buffer age(>0) to merge history
246 int32_t bufferAge = surfaceFrame->GetBufferAge();
247 if (!curDirtyManager_->SetBufferAge(bufferAge)) {
248 ROSEN_LOGD("ProcessRootRenderNode SetBufferAge with invalid buffer age %d", bufferAge);
249 curDirtyManager_->ResetDirtyAsSurfaceSize();
250 }
251 curDirtyManager_->UpdateDirtyByAligned();
252 curDirtyManager_->UpdateDirty();
253 curDirtyRegion_ = curDirtyManager_->GetDirtyRegion();
254 // only set damage region if dirty region and buffer age is valid(>0)
255 if (bufferAge >= 0) {
256 // get dirty rect coordinated from upper left to lower left corner in current surface
257 RectI dirtyRectFlip = curDirtyManager_->GetRectFlipWithinSurface(curDirtyRegion_);
258 // set dirty rect as eglSurfaceFrame's damage region
259 surfaceFrame->SetDamageRegion(dirtyRectFlip.left_, dirtyRectFlip.top_, dirtyRectFlip.width_,
260 dirtyRectFlip.height_);
261 // flip aligned rect for op drops
262 curDirtyRegion_ = curDirtyManager_->GetRectFlipWithinSurface(dirtyRectFlip);
263 ROSEN_LOGD("GetPartialRenderEnabled buffer age %d, dirtyRectFlip = [%d, %d, %d, %d], "
264 "dirtyRectAlign = [%d, %d, %d, %d]", bufferAge,
265 dirtyRectFlip.left_, dirtyRectFlip.top_, dirtyRectFlip.width_, dirtyRectFlip.height_,
266 curDirtyRegion_.left_, curDirtyRegion_.top_, curDirtyRegion_.width_, curDirtyRegion_.height_);
267 }
268 } else {
269 curDirtyManager_->UpdateDirty();
270 curDirtyRegion_ = curDirtyManager_->GetDirtyRegion();
271 }
272 #else
273 curDirtyManager_->UpdateDirty();
274 curDirtyRegion_ = curDirtyManager_->GetDirtyRegion();
275 #endif
276 ROSEN_LOGD("UpdateDirtyAndSetEGLDamageRegion dirtyRect = [%d, %d, %d, %d]",
277 curDirtyRegion_.left_, curDirtyRegion_.top_, curDirtyRegion_.width_, curDirtyRegion_.height_);
278 RS_TRACE_END();
279 }
280
ProcessBaseRenderNode(RSBaseRenderNode & node)281 void RSRenderThreadVisitor::ProcessBaseRenderNode(RSBaseRenderNode& node)
282 {
283 for (auto& child : node.GetSortedChildren()) {
284 child->Process(shared_from_this());
285 }
286 // clear SortedChildren, it will be generated again in next frame
287 node.ResetSortedChildren();
288 }
289
ProcessRootRenderNode(RSRootRenderNode & node)290 void RSRenderThreadVisitor::ProcessRootRenderNode(RSRootRenderNode& node)
291 {
292 if (!isIdle_) {
293 ProcessCanvasRenderNode(node);
294 return;
295 }
296 auto ptr = RSNodeMap::Instance().GetNode<RSSurfaceNode>(node.GetRSSurfaceNodeId());
297 if (!IsValidRootRenderNode(node)) {
298 return;
299 }
300
301 curDirtyManager_ = node.GetDirtyManager();
302
303 #if !defined(_WIN32) && !defined(__APPLE__) && !defined(__gnu_linux__)
304 auto surfaceNodeColorSpace = ptr->GetColorSpace();
305 #endif
306 std::shared_ptr<RSSurface> rsSurface = RSSurfaceExtractor::ExtractRSSurface(ptr);
307 if (rsSurface == nullptr) {
308 ROSEN_LOGE("ProcessRoot %s: No RSSurface found", ptr->GetName().c_str());
309 return;
310 }
311 // Update queue size for each process loop in case it dynamically changes
312 queueSize_ = rsSurface->GetQueueSize();
313
314 #if !defined(_WIN32) && !defined(__APPLE__) && !defined(__gnu_linux__)
315 auto rsSurfaceColorSpace = rsSurface->GetColorSpace();
316 if (surfaceNodeColorSpace != rsSurfaceColorSpace) {
317 ROSEN_LOGD("Set new colorspace %d to rsSurface", surfaceNodeColorSpace);
318 rsSurface->SetColorSpace(surfaceNodeColorSpace);
319 }
320 #endif
321
322 #ifdef ACE_ENABLE_GL
323 RenderContext* rc = RSRenderThread::Instance().GetRenderContext();
324 rsSurface->SetRenderContext(rc);
325 #endif
326 uiTimestamp_ = RSRenderThread::Instance().GetUITimestamp();
327 RS_TRACE_BEGIN(ptr->GetName() + " rsSurface->RequestFrame");
328 #ifdef ROSEN_OHOS
329 FrameCollector::GetInstance().MarkFrameEvent(FrameEventType::ReleaseStart);
330 #endif
331
332 const auto& property = node.GetRenderProperties();
333 const float bufferWidth = node.GetSuggestedBufferWidth() * property.GetScaleX();
334 const float bufferHeight = node.GetSuggestedBufferHeight() * property.GetScaleY();
335 #ifdef ROSEN_OHOS
336 auto surfaceFrame = rsSurface->RequestFrame(bufferWidth, bufferHeight, uiTimestamp_);
337 #else
338 auto surfaceFrame = rsSurface->RequestFrame(std::round(bufferWidth), std::round(bufferHeight), uiTimestamp_);
339 #endif
340 RS_TRACE_END();
341 if (surfaceFrame == nullptr) {
342 ROSEN_LOGI("ProcessRoot %s: Request Frame Failed", ptr->GetName().c_str());
343 #ifdef ROSEN_OHOS
344 FrameCollector::GetInstance().MarkFrameEvent(FrameEventType::ReleaseEnd);
345 #endif
346 return;
347 }
348
349 auto skSurface = surfaceFrame->GetSurface();
350 if (skSurface == nullptr) {
351 ROSEN_LOGE("skSurface null.");
352 return;
353 }
354 if (skSurface->getCanvas() == nullptr) {
355 ROSEN_LOGE("skSurface.getCanvas is null.");
356 return;
357 }
358
359 #ifdef ROSEN_OHOS
360 // if listenedCanvas is nullptr, that means disabled or listen failed
361 std::shared_ptr<RSListenedCanvas> listenedCanvas = nullptr;
362 std::shared_ptr<RSCanvasListener> overdrawListener = nullptr;
363
364 if (RSOverdrawController::GetInstance().IsEnabled()) {
365 auto &oc = RSOverdrawController::GetInstance();
366 listenedCanvas = std::make_shared<RSListenedCanvas>(skSurface.get());
367 overdrawListener = oc.CreateListener<RSGPUOverdrawCanvasListener>(listenedCanvas.get());
368 if (overdrawListener == nullptr) {
369 overdrawListener = oc.CreateListener<RSCPUOverdrawCanvasListener>(listenedCanvas.get());
370 }
371
372 if (overdrawListener != nullptr) {
373 listenedCanvas->SetListener(overdrawListener);
374 } else {
375 // create listener failed
376 listenedCanvas = nullptr;
377 }
378 }
379
380 if (listenedCanvas != nullptr) {
381 canvas_ = listenedCanvas;
382 } else {
383 canvas_ = std::make_shared<RSPaintFilterCanvas>(skSurface.get());
384 }
385 #else
386 canvas_ = std::make_shared<RSPaintFilterCanvas>(skSurface.get());
387 #endif
388
389 canvas_->SetHighContrast(RSRenderThread::Instance().isHighContrastEnabled());
390
391 // node's surface size already check, so here we do not need to check return
392 // attention: currently surfaceW/H are float values transformed into int implicitly
393 (void)curDirtyManager_->SetSurfaceSize(bufferWidth, bufferHeight);
394 // keep non-negative rect region within surface
395 curDirtyManager_->ClipDirtyRectWithinSurface();
396 // reset matrix
397 const float rootWidth = property.GetFrameWidth() * property.GetScaleX();
398 const float rootHeight = property.GetFrameHeight() * property.GetScaleY();
399 SkMatrix gravityMatrix;
400 (void)RSPropertiesPainter::GetGravityMatrix(
401 Gravity::RESIZE, RectF { 0.0f, 0.0f, bufferWidth, bufferHeight }, rootWidth, rootHeight, gravityMatrix);
402
403 if (isRenderForced_ ||
404 curDirtyManager_->GetDirtyRegion().GetWidth() == 0 ||
405 curDirtyManager_->GetDirtyRegion().GetHeight() == 0 ||
406 !gravityMatrix.isIdentity()) {
407 curDirtyManager_->ResetDirtyAsSurfaceSize();
408 }
409 UpdateDirtyAndSetEGLDamageRegion(surfaceFrame);
410
411 canvas_->clipRect(SkRect::MakeWH(bufferWidth, bufferHeight));
412 canvas_->clear(SK_ColorTRANSPARENT);
413 isIdle_ = false;
414
415 // clear current children before traversal, we will re-add them again during traversal
416 childSurfaceNodeIds_.clear();
417
418 canvas_->concat(gravityMatrix);
419 parentSurfaceNodeMatrix_ = gravityMatrix;
420
421 RS_TRACE_BEGIN("ProcessRenderNodes");
422 needUpdateSurfaceNode_ = node.GetNeedUpdateSurfaceNode();
423 ProcessCanvasRenderNode(node);
424
425 if (childSurfaceNodeIds_ != node.childSurfaceNodeIds_ || needUpdateSurfaceNode_) {
426 auto thisSurfaceNodeId = node.GetRSSurfaceNodeId();
427 std::unique_ptr<RSCommand> command = std::make_unique<RSBaseNodeClearSurfaceNodeChild>(thisSurfaceNodeId);
428 SendCommandFromRT(command, thisSurfaceNodeId, FollowType::FOLLOW_VISITOR);
429 for (const auto& childSurfaceNodeId : childSurfaceNodeIds_) {
430 command = std::make_unique<RSBaseNodeAddChild>(thisSurfaceNodeId, childSurfaceNodeId, -1);
431 SendCommandFromRT(command, thisSurfaceNodeId, FollowType::FOLLOW_VISITOR);
432 }
433 node.childSurfaceNodeIds_ = std::move(childSurfaceNodeIds_);
434 }
435 needUpdateSurfaceNode_ = false;
436 node.SetNeedUpdateSurfaceNode(false);
437 RS_TRACE_END();
438
439 auto transactionProxy = RSTransactionProxy::GetInstance();
440 if (transactionProxy != nullptr) {
441 ROSEN_LOGD("RSRenderThreadVisitor FlushImplicitTransactionFromRT uiTimestamp = %" PRIu64, uiTimestamp_);
442 transactionProxy->FlushImplicitTransactionFromRT(uiTimestamp_);
443 }
444
445 if (curDirtyManager_->IsDirty() && curDirtyManager_->IsDebugEnabled()) {
446 ROSEN_LOGD("ProcessRootRenderNode %s [%" PRIu64 "] draw dirtyRect", ptr->GetName().c_str(), node.GetId());
447 DrawDirtyRegion();
448 }
449
450 #ifdef ROSEN_OHOS
451 if (overdrawListener != nullptr) {
452 overdrawListener->Draw();
453 }
454
455 FramePainter fpainter(FrameCollector::GetInstance());
456 fpainter.Draw(*canvas_);
457 FrameCollector::GetInstance().MarkFrameEvent(FrameEventType::ReleaseEnd);
458 FrameCollector::GetInstance().MarkFrameEvent(FrameEventType::FlushStart);
459 #endif
460
461 RS_TRACE_BEGIN(ptr->GetName() + " rsSurface->FlushFrame");
462 ROSEN_LOGD("RSRenderThreadVisitor FlushFrame surfaceNodeId = %" PRIu64 ", uiTimestamp = %" PRIu64,
463 node.GetRSSurfaceNodeId(), uiTimestamp_);
464 rsSurface->FlushFrame(surfaceFrame, uiTimestamp_);
465 #ifdef ROSEN_OHOS
466 FrameCollector::GetInstance().MarkFrameEvent(FrameEventType::FlushEnd);
467 #endif
468 RS_TRACE_END();
469
470 canvas_ = nullptr;
471 isIdle_ = true;
472 }
473
ProcessCanvasRenderNode(RSCanvasRenderNode & node)474 void RSRenderThreadVisitor::ProcessCanvasRenderNode(RSCanvasRenderNode& node)
475 {
476 if (!node.ShouldPaint()) {
477 return;
478 }
479 if (!canvas_) {
480 ROSEN_LOGE("RSRenderThreadVisitor::ProcessCanvasRenderNode, canvas is nullptr");
481 return;
482 }
483 node.UpdateRenderStatus(curDirtyRegion_, isOpDropped_);
484 if (node.IsRenderUpdateIgnored()) {
485 return;
486 }
487 node.ProcessRenderBeforeChildren(*canvas_);
488 ProcessBaseRenderNode(node);
489 node.ProcessRenderAfterChildren(*canvas_);
490 }
491
getLocalClipBounds(RSPaintFilterCanvas * canvas)492 static SkRect getLocalClipBounds(RSPaintFilterCanvas* canvas)
493 {
494 SkIRect ibounds = canvas->getDeviceClipBounds();
495 if (ibounds.isEmpty()) {
496 return SkRect::MakeEmpty();
497 }
498
499 SkMatrix inverse;
500 // if we can't invert the CTM, we can't return local clip bounds
501 if (!(canvas->getTotalMatrix().invert(&inverse))) {
502 return SkRect::MakeEmpty();
503 }
504 SkRect bounds;
505 SkRect r = SkRect::Make(ibounds);
506 inverse.mapRect(&bounds, r);
507 return bounds;
508 }
509
ProcessSurfaceRenderNode(RSSurfaceRenderNode & node)510 void RSRenderThreadVisitor::ProcessSurfaceRenderNode(RSSurfaceRenderNode& node)
511 {
512 if (!canvas_) {
513 ROSEN_LOGE("RSRenderThreadVisitor::ProcessSurfaceRenderNode, canvas is nullptr");
514 return;
515 }
516 if (!node.ShouldPaint()) {
517 ROSEN_LOGI("RSRenderThreadVisitor::ProcessSurfaceRenderNode node : %" PRIu64 " is invisible", node.GetId());
518 node.SetContextAlpha(0.0f);
519 return;
520 }
521 // RSSurfaceRenderNode in RSRenderThreadVisitor do not have information of property.
522 // We only get parent's matrix and send it to RenderService
523 SkMatrix invertMatrix;
524 SkMatrix contextMatrix = canvas_->getTotalMatrix();
525
526 if (parentSurfaceNodeMatrix_.invert(&invertMatrix)) {
527 contextMatrix.preConcat(invertMatrix);
528 } else {
529 ROSEN_LOGE("RSRenderThreadVisitor::ProcessSurfaceRenderNode, invertMatrix failed");
530 }
531 node.SetContextMatrix(contextMatrix);
532 node.SetContextAlpha(canvas_->GetAlpha());
533
534 // PLANNING: This is a temporary modification. Animation for surfaceView should not be triggered in RenderService.
535 // We plan to refactor code here.
536 node.SetContextBounds(node.GetRenderProperties().GetBounds());
537
538 auto clipRect = getLocalClipBounds(canvas_.get());
539 if (clipRect.width() < std::numeric_limits<float>::epsilon() ||
540 clipRect.height() < std::numeric_limits<float>::epsilon()) {
541 // if clipRect is empty, this node will be removed from parent's children list.
542 return;
543 }
544 node.SetContextClipRegion(clipRect);
545
546 // clip hole
547 ClipHoleForSurfaceNode(node);
548
549 // 1. add this node to parent's children list
550 childSurfaceNodeIds_.emplace_back(node.GetId());
551
552 // 2. backup and reset environment variables before traversal children
553 std::vector<NodeId> siblingSurfaceNodeIds(std::move(childSurfaceNodeIds_));
554 childSurfaceNodeIds_.clear();
555 auto parentSurfaceNodeMatrix = parentSurfaceNodeMatrix_;
556 parentSurfaceNodeMatrix_ = canvas_->getTotalMatrix();
557
558 // 3. traversal children, child surface node will be added to childSurfaceNodeIds_
559 // note: apply current node properties onto canvas if there is any child node
560 ProcessBaseRenderNode(node);
561
562 // 4. if children changed, sync children to RenderService
563 if (childSurfaceNodeIds_ != node.childSurfaceNodeIds_ || needUpdateSurfaceNode_) {
564 auto thisSurfaceNodeId = node.GetId();
565 std::unique_ptr<RSCommand> command = std::make_unique<RSBaseNodeClearSurfaceNodeChild>(thisSurfaceNodeId);
566 SendCommandFromRT(command, thisSurfaceNodeId, FollowType::FOLLOW_VISITOR);
567 for (const auto& childSurfaceNodeId : childSurfaceNodeIds_) {
568 command = std::make_unique<RSBaseNodeAddChild>(thisSurfaceNodeId, childSurfaceNodeId, -1);
569 SendCommandFromRT(command, thisSurfaceNodeId, FollowType::FOLLOW_VISITOR);
570 }
571 node.childSurfaceNodeIds_ = std::move(childSurfaceNodeIds_);
572 }
573
574 // 5. restore environments variables before continue traversal siblings
575 childSurfaceNodeIds_ = std::move(siblingSurfaceNodeIds);
576 parentSurfaceNodeMatrix_ = parentSurfaceNodeMatrix;
577 }
578
ProcessProxyRenderNode(RSProxyRenderNode & node)579 void RSRenderThreadVisitor::ProcessProxyRenderNode(RSProxyRenderNode& node)
580 {
581 if (!canvas_) {
582 ROSEN_LOGE("RSRenderThreadVisitor::ProcessProxyRenderNode, canvas is nullptr");
583 return;
584 }
585 // RSProxyRenderNode in RSRenderThreadVisitor do not have information of property.
586 // We only get parent's matrix and send it to RenderService
587 #ifdef ROSEN_OHOS
588 SkMatrix invertMatrix;
589 SkMatrix contextMatrix = canvas_->getTotalMatrix();
590
591 if (parentSurfaceNodeMatrix_.invert(&invertMatrix)) {
592 contextMatrix.preConcat(invertMatrix);
593 } else {
594 ROSEN_LOGE("RSRenderThreadVisitor::ProcessProxyRenderNode, invertMatrix failed");
595 }
596 node.SetContextMatrix(contextMatrix);
597 node.SetContextAlpha(canvas_->GetAlpha());
598
599 // for proxied nodes (i.e. remote window components), we only extract matrix & alpha, do not change their hierarchy
600 // or clip or other properties.
601 node.ResetSortedChildren();
602 #endif
603 }
604
ClipHoleForSurfaceNode(RSSurfaceRenderNode & node)605 void RSRenderThreadVisitor::ClipHoleForSurfaceNode(RSSurfaceRenderNode& node)
606 {
607 // Calculation position in RenderService may appear floating point number, and it will be removed.
608 // It caused missed line problem on surfaceview hap, so we subtract one pixel when cliphole to avoid this problem
609 static int pixel = 1;
610 auto x = std::ceil(node.GetRenderProperties().GetBoundsPositionX() + pixel); // x increase 1 pixel
611 auto y = std::ceil(node.GetRenderProperties().GetBoundsPositionY() + pixel); // y increase 1 pixel
612 auto width = std::floor(node.GetRenderProperties().GetBoundsWidth() - (2 * pixel)); // width decrease 2 pixels
613 auto height = std::floor(node.GetRenderProperties().GetBoundsHeight() - (2 * pixel)); // height decrease 2 pixels
614 canvas_->save();
615 SkRect originRect = SkRect::MakeXYWH(x, y, width, height);
616 canvas_->clipRect(originRect);
617 if (node.IsNotifyRTBufferAvailable()) {
618 ROSEN_LOGD("RSRenderThreadVisitor::ClipHoleForSurfaceNode node : %" PRIu64 ", clip [%f, %f, %f, %f]",
619 node.GetId(), x, y, width, height);
620 canvas_->clear(SK_ColorTRANSPARENT);
621 } else {
622 ROSEN_LOGD("RSRenderThreadVisitor::ClipHoleForSurfaceNode node : %" PRIu64 ", not clip [%f, %f, %f, %f]",
623 node.GetId(), x, y, width, height);
624 auto backgroundColor = node.GetRenderProperties().GetBackgroundColor();
625 if (backgroundColor != RgbPalette::Transparent()) {
626 canvas_->clear(backgroundColor.AsArgbInt());
627 }
628 }
629 canvas_->restore();
630 }
631
SendCommandFromRT(std::unique_ptr<RSCommand> & command,NodeId nodeId,FollowType followType)632 void RSRenderThreadVisitor::SendCommandFromRT(std::unique_ptr<RSCommand>& command, NodeId nodeId, FollowType followType)
633 {
634 auto transactionProxy = RSTransactionProxy::GetInstance();
635 if (transactionProxy != nullptr) {
636 transactionProxy->AddCommandFromRT(command, nodeId, followType);
637 }
638 }
639 } // namespace Rosen
640 } // namespace OHOS
641