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 auto surfaceFrame = rsSurface->RequestFrame(bufferWidth, bufferHeight, uiTimestamp_);
336 RS_TRACE_END();
337 if (surfaceFrame == nullptr) {
338 ROSEN_LOGI("ProcessRoot %s: Request Frame Failed", ptr->GetName().c_str());
339 #ifdef ROSEN_OHOS
340 FrameCollector::GetInstance().MarkFrameEvent(FrameEventType::ReleaseEnd);
341 #endif
342 return;
343 }
344
345 auto skSurface = surfaceFrame->GetSurface();
346 if (skSurface == nullptr) {
347 ROSEN_LOGE("skSurface null.");
348 return;
349 }
350 if (skSurface->getCanvas() == nullptr) {
351 ROSEN_LOGE("skSurface.getCanvas is null.");
352 return;
353 }
354
355 #ifdef ROSEN_OHOS
356 // if listenedCanvas is nullptr, that means disabled or listen failed
357 std::shared_ptr<RSListenedCanvas> listenedCanvas = nullptr;
358 std::shared_ptr<RSCanvasListener> overdrawListener = nullptr;
359
360 if (RSOverdrawController::GetInstance().IsEnabled()) {
361 auto &oc = RSOverdrawController::GetInstance();
362 listenedCanvas = std::make_shared<RSListenedCanvas>(skSurface.get());
363 overdrawListener = oc.CreateListener<RSGPUOverdrawCanvasListener>(listenedCanvas.get());
364 if (overdrawListener == nullptr) {
365 overdrawListener = oc.CreateListener<RSCPUOverdrawCanvasListener>(listenedCanvas.get());
366 }
367
368 if (overdrawListener != nullptr) {
369 listenedCanvas->SetListener(overdrawListener);
370 } else {
371 // create listener failed
372 listenedCanvas = nullptr;
373 }
374 }
375
376 if (listenedCanvas != nullptr) {
377 canvas_ = listenedCanvas;
378 } else {
379 canvas_ = std::make_shared<RSPaintFilterCanvas>(skSurface.get());
380 }
381 #else
382 canvas_ = std::make_shared<RSPaintFilterCanvas>(skSurface.get());
383 #endif
384
385 canvas_->SetHighContrast(RSRenderThread::Instance().isHighContrastEnabled());
386
387 // node's surface size already check, so here we do not need to check return
388 // attention: currently surfaceW/H are float values transformed into int implicitly
389 (void)curDirtyManager_->SetSurfaceSize(bufferWidth, bufferHeight);
390 // keep non-negative rect region within surface
391 curDirtyManager_->ClipDirtyRectWithinSurface();
392 // reset matrix
393 const float rootWidth = property.GetFrameWidth() * property.GetScaleX();
394 const float rootHeight = property.GetFrameHeight() * property.GetScaleY();
395 SkMatrix gravityMatrix;
396 (void)RSPropertiesPainter::GetGravityMatrix(
397 Gravity::RESIZE, RectF { 0.0f, 0.0f, bufferWidth, bufferHeight }, rootWidth, rootHeight, gravityMatrix);
398
399 if (isRenderForced_ ||
400 curDirtyManager_->GetDirtyRegion().GetWidth() == 0 ||
401 curDirtyManager_->GetDirtyRegion().GetHeight() == 0 ||
402 !gravityMatrix.isIdentity()) {
403 curDirtyManager_->ResetDirtyAsSurfaceSize();
404 }
405 UpdateDirtyAndSetEGLDamageRegion(surfaceFrame);
406
407 canvas_->clipRect(SkRect::MakeWH(bufferWidth, bufferHeight));
408 canvas_->clear(SK_ColorTRANSPARENT);
409 isIdle_ = false;
410
411 // clear current children before traversal, we will re-add them again during traversal
412 childSurfaceNodeIds_.clear();
413
414 canvas_->concat(gravityMatrix);
415 parentSurfaceNodeMatrix_ = gravityMatrix;
416
417 RS_TRACE_BEGIN("ProcessRenderNodes");
418 needUpdateSurfaceNode_ = node.GetNeedUpdateSurfaceNode();
419 ProcessCanvasRenderNode(node);
420
421 if (childSurfaceNodeIds_ != node.childSurfaceNodeIds_ || needUpdateSurfaceNode_) {
422 auto thisSurfaceNodeId = node.GetRSSurfaceNodeId();
423 std::unique_ptr<RSCommand> command = std::make_unique<RSBaseNodeClearSurfaceNodeChild>(thisSurfaceNodeId);
424 SendCommandFromRT(command, thisSurfaceNodeId, FollowType::FOLLOW_VISITOR);
425 for (const auto& childSurfaceNodeId : childSurfaceNodeIds_) {
426 command = std::make_unique<RSBaseNodeAddChild>(thisSurfaceNodeId, childSurfaceNodeId, -1);
427 SendCommandFromRT(command, thisSurfaceNodeId, FollowType::FOLLOW_VISITOR);
428 }
429 node.childSurfaceNodeIds_ = std::move(childSurfaceNodeIds_);
430 }
431 needUpdateSurfaceNode_ = false;
432 node.SetNeedUpdateSurfaceNode(false);
433 RS_TRACE_END();
434
435 auto transactionProxy = RSTransactionProxy::GetInstance();
436 if (transactionProxy != nullptr) {
437 ROSEN_LOGD("RSRenderThreadVisitor FlushImplicitTransactionFromRT uiTimestamp = %" PRIu64, uiTimestamp_);
438 transactionProxy->FlushImplicitTransactionFromRT(uiTimestamp_);
439 }
440
441 if (curDirtyManager_->IsDirty() && curDirtyManager_->IsDebugEnabled()) {
442 ROSEN_LOGD("ProcessRootRenderNode %s [%" PRIu64 "] draw dirtyRect", ptr->GetName().c_str(), node.GetId());
443 DrawDirtyRegion();
444 }
445
446 #ifdef ROSEN_OHOS
447 if (overdrawListener != nullptr) {
448 overdrawListener->Draw();
449 }
450
451 FramePainter fpainter(FrameCollector::GetInstance());
452 fpainter.Draw(*canvas_);
453 FrameCollector::GetInstance().MarkFrameEvent(FrameEventType::ReleaseEnd);
454 FrameCollector::GetInstance().MarkFrameEvent(FrameEventType::FlushStart);
455 #endif
456
457 RS_TRACE_BEGIN(ptr->GetName() + " rsSurface->FlushFrame");
458 ROSEN_LOGD("RSRenderThreadVisitor FlushFrame surfaceNodeId = %" PRIu64 ", uiTimestamp = %" PRIu64,
459 node.GetRSSurfaceNodeId(), uiTimestamp_);
460 rsSurface->FlushFrame(surfaceFrame, uiTimestamp_);
461 #ifdef ROSEN_OHOS
462 FrameCollector::GetInstance().MarkFrameEvent(FrameEventType::FlushEnd);
463 #endif
464 RS_TRACE_END();
465
466 canvas_ = nullptr;
467 isIdle_ = true;
468 }
469
ProcessCanvasRenderNode(RSCanvasRenderNode & node)470 void RSRenderThreadVisitor::ProcessCanvasRenderNode(RSCanvasRenderNode& node)
471 {
472 if (!node.ShouldPaint()) {
473 return;
474 }
475 if (!canvas_) {
476 ROSEN_LOGE("RSRenderThreadVisitor::ProcessCanvasRenderNode, canvas is nullptr");
477 return;
478 }
479 node.UpdateRenderStatus(curDirtyRegion_, isOpDropped_);
480 if (node.IsRenderUpdateIgnored()) {
481 return;
482 }
483 node.ProcessRenderBeforeChildren(*canvas_);
484 ProcessBaseRenderNode(node);
485 node.ProcessRenderAfterChildren(*canvas_);
486 }
487
getLocalClipBounds(RSPaintFilterCanvas * canvas)488 static SkRect getLocalClipBounds(RSPaintFilterCanvas* canvas)
489 {
490 SkIRect ibounds = canvas->getDeviceClipBounds();
491 if (ibounds.isEmpty()) {
492 return SkRect::MakeEmpty();
493 }
494
495 SkMatrix inverse;
496 // if we can't invert the CTM, we can't return local clip bounds
497 if (!(canvas->getTotalMatrix().invert(&inverse))) {
498 return SkRect::MakeEmpty();
499 }
500 SkRect bounds;
501 SkRect r = SkRect::Make(ibounds);
502 inverse.mapRect(&bounds, r);
503 return bounds;
504 }
505
ProcessSurfaceRenderNode(RSSurfaceRenderNode & node)506 void RSRenderThreadVisitor::ProcessSurfaceRenderNode(RSSurfaceRenderNode& node)
507 {
508 if (!canvas_) {
509 ROSEN_LOGE("RSRenderThreadVisitor::ProcessSurfaceRenderNode, canvas is nullptr");
510 return;
511 }
512 if (!node.ShouldPaint()) {
513 ROSEN_LOGI("RSRenderThreadVisitor::ProcessSurfaceRenderNode node : %" PRIu64 " is invisible", node.GetId());
514 node.SetContextAlpha(0.0f);
515 return;
516 }
517 // RSSurfaceRenderNode in RSRenderThreadVisitor do not have information of property.
518 // We only get parent's matrix and send it to RenderService
519 SkMatrix invertMatrix;
520 SkMatrix contextMatrix = canvas_->getTotalMatrix();
521
522 if (parentSurfaceNodeMatrix_.invert(&invertMatrix)) {
523 contextMatrix.preConcat(invertMatrix);
524 } else {
525 ROSEN_LOGE("RSRenderThreadVisitor::ProcessSurfaceRenderNode, invertMatrix failed");
526 }
527 node.SetContextMatrix(contextMatrix);
528 node.SetContextAlpha(canvas_->GetAlpha());
529
530 // PLANNING: This is a temporary modification. Animation for surfaceView should not be triggered in RenderService.
531 // We plan to refactor code here.
532 node.SetContextBounds(node.GetRenderProperties().GetBounds());
533
534 auto clipRect = getLocalClipBounds(canvas_.get());
535 if (clipRect.width() < std::numeric_limits<float>::epsilon() ||
536 clipRect.height() < std::numeric_limits<float>::epsilon()) {
537 // if clipRect is empty, this node will be removed from parent's children list.
538 return;
539 }
540 node.SetContextClipRegion(clipRect);
541
542 // clip hole
543 ClipHoleForSurfaceNode(node);
544
545 // 1. add this node to parent's children list
546 childSurfaceNodeIds_.emplace_back(node.GetId());
547
548 // 2. backup and reset environment variables before traversal children
549 std::vector<NodeId> siblingSurfaceNodeIds(std::move(childSurfaceNodeIds_));
550 childSurfaceNodeIds_.clear();
551 auto parentSurfaceNodeMatrix = parentSurfaceNodeMatrix_;
552 parentSurfaceNodeMatrix_ = canvas_->getTotalMatrix();
553
554 // 3. traversal children, child surface node will be added to childSurfaceNodeIds_
555 // note: apply current node properties onto canvas if there is any child node
556 ProcessBaseRenderNode(node);
557
558 // 4. if children changed, sync children to RenderService
559 if (childSurfaceNodeIds_ != node.childSurfaceNodeIds_ || needUpdateSurfaceNode_) {
560 auto thisSurfaceNodeId = node.GetId();
561 std::unique_ptr<RSCommand> command = std::make_unique<RSBaseNodeClearSurfaceNodeChild>(thisSurfaceNodeId);
562 SendCommandFromRT(command, thisSurfaceNodeId, FollowType::FOLLOW_VISITOR);
563 for (const auto& childSurfaceNodeId : childSurfaceNodeIds_) {
564 command = std::make_unique<RSBaseNodeAddChild>(thisSurfaceNodeId, childSurfaceNodeId, -1);
565 SendCommandFromRT(command, thisSurfaceNodeId, FollowType::FOLLOW_VISITOR);
566 }
567 node.childSurfaceNodeIds_ = std::move(childSurfaceNodeIds_);
568 }
569
570 // 5. restore environments variables before continue traversal siblings
571 childSurfaceNodeIds_ = std::move(siblingSurfaceNodeIds);
572 parentSurfaceNodeMatrix_ = parentSurfaceNodeMatrix;
573 }
574
ProcessProxyRenderNode(RSProxyRenderNode & node)575 void RSRenderThreadVisitor::ProcessProxyRenderNode(RSProxyRenderNode& node)
576 {
577 if (!canvas_) {
578 ROSEN_LOGE("RSRenderThreadVisitor::ProcessProxyRenderNode, canvas is nullptr");
579 return;
580 }
581 // RSProxyRenderNode in RSRenderThreadVisitor do not have information of property.
582 // We only get parent's matrix and send it to RenderService
583 #ifdef ROSEN_OHOS
584 SkMatrix invertMatrix;
585 SkMatrix contextMatrix = canvas_->getTotalMatrix();
586
587 if (parentSurfaceNodeMatrix_.invert(&invertMatrix)) {
588 contextMatrix.preConcat(invertMatrix);
589 } else {
590 ROSEN_LOGE("RSRenderThreadVisitor::ProcessProxyRenderNode, invertMatrix failed");
591 }
592 node.SetContextMatrix(contextMatrix);
593 node.SetContextAlpha(canvas_->GetAlpha());
594
595 // for proxied nodes (i.e. remote window components), we only extract matrix & alpha, do not change their hierarchy
596 // or clip or other properties.
597 node.ResetSortedChildren();
598 #endif
599 }
600
ClipHoleForSurfaceNode(RSSurfaceRenderNode & node)601 void RSRenderThreadVisitor::ClipHoleForSurfaceNode(RSSurfaceRenderNode& node)
602 {
603 // Calculation position in RenderService may appear floating point number, and it will be removed.
604 // It caused missed line problem on surfaceview hap, so we subtract one pixel when cliphole to avoid this problem
605 static int pixel = 1;
606 auto x = std::ceil(node.GetRenderProperties().GetBoundsPositionX() + pixel); // x increase 1 pixel
607 auto y = std::ceil(node.GetRenderProperties().GetBoundsPositionY() + pixel); // y increase 1 pixel
608 auto width = std::floor(node.GetRenderProperties().GetBoundsWidth() - (2 * pixel)); // width decrease 2 pixels
609 auto height = std::floor(node.GetRenderProperties().GetBoundsHeight() - (2 * pixel)); // height decrease 2 pixels
610 canvas_->save();
611 SkRect originRect = SkRect::MakeXYWH(x, y, width, height);
612 canvas_->clipRect(originRect);
613 if (node.IsNotifyRTBufferAvailable()) {
614 ROSEN_LOGD("RSRenderThreadVisitor::ClipHoleForSurfaceNode node : %" PRIu64 ", clip [%f, %f, %f, %f]",
615 node.GetId(), x, y, width, height);
616 canvas_->clear(SK_ColorTRANSPARENT);
617 } else {
618 ROSEN_LOGD("RSRenderThreadVisitor::ClipHoleForSurfaceNode node : %" PRIu64 ", not clip [%f, %f, %f, %f]",
619 node.GetId(), x, y, width, height);
620 auto backgroundColor = node.GetRenderProperties().GetBackgroundColor();
621 if (backgroundColor != RgbPalette::Transparent()) {
622 canvas_->clear(backgroundColor.AsArgbInt());
623 }
624 }
625 canvas_->restore();
626 }
627
SendCommandFromRT(std::unique_ptr<RSCommand> & command,NodeId nodeId,FollowType followType)628 void RSRenderThreadVisitor::SendCommandFromRT(std::unique_ptr<RSCommand>& command, NodeId nodeId, FollowType followType)
629 {
630 auto transactionProxy = RSTransactionProxy::GetInstance();
631 if (transactionProxy != nullptr) {
632 transactionProxy->AddCommandFromRT(command, nodeId, followType);
633 }
634 }
635 } // namespace Rosen
636 } // namespace OHOS
637