系列文章目录

针对源码解析一:旋转值来解决一个bug
文章目录
前言
提示:初始化流程可以参考 源码解析一
一、DMS流程
DMS(Display Manager Service)在启动阶段的核心职责是构建显示拓扑并同步渲染状态。其工作流程如下:
1、屏幕发现与抽象 :通过 RSInterface 注册屏幕连接回调。一旦检测到物理屏幕连接,立即实例化 AbsScreen,并通过接口获取分辨率、刷新率等硬件参数完成初始化。
2、组管理与节点创建 :创建 ScreenGroup 并将 AbsScreen 纳入管理。随后,为屏幕初始化对应的 RSDisplayNode,并向 RenderService 提交事务以确立渲染树节点。
cpp
/* 这里根据rotationAfter数值来设旋转值给node */
void AbstractScreenController::SetDisplayNode(Rotation rotationAfter,
const std::shared_ptr<RSDisplayNode>& displayNode, struct ScreenRect srect)
{
displayNode->SetRotation(-90.f * static_cast<uint32_t>(rotationAfter)); // 90.f is base degree
/* 这里有node 的setFrame和setBounds 两个Rect */
displayNode->SetFrame(srect.x, srect.y, srect.w, srect.h);
displayNode->SetBounds(srect.x, srect.y, srect.w, srect.h);
}
3、逻辑显示构建 :基于初始化完成的 AbsScreen,创建 AbstractDisplay 对象。该对象不仅继承物理屏的参数,还依据宽高比例计算虚拟像素比 (Virtual Pixel Ratio),最终广播"Display 就绪"事件通知各订阅方。
4、窗口系统联动 :WMS 监听 DMS 的 Display 变更事件(如尺寸调整、横竖屏切换)。收到通知后,WMS 驱动 WindowNodeContainer 更新 Display 状态并触发全局窗口重布局。
5、生命周期协同:当触发 BEFORE_SUSPEND 事件(如进入锁屏)时,WMS 经由 WindowNodeContainer 将所有窗口 (WindowImpl) 状态置为 STATE_FROZEN,同时通知 AMS 将持有窗口的 Ability 迁移至后台,确保系统资源有序释放。
二、RS流程
- 启动准备 :
RSRenderService::Init()初始化主线程、ScreenManager 和运行时环境,但不创建屏幕。 - 屏幕绑定 :DMS 调用
CreateDisplayNode(screenId),RS 通过 HDI 查询屏参,在 DMS 要求下RSDisplayNode和RSPhysicalScreenProcessor。 - 渲染提交 :UI 调用
Flush()触发合成,RSPhysicalScreenProcessor收集图层并调用CommitLayers()提交到 HDI 硬件显示。
三、横屏旋转异常
现象:屏幕旋转配置未生效,且显示画面出现异常裁剪,呈现为正方形。
原因
1、node并没有传旋转值给到 RS,这里具体是RSRenderServiceVisitor:
cpp
void RSRenderServiceVisitor::PrepareScreenRenderNode(RSScreenRenderNode& node)
{
/* 获取id */
currentVisitDisplay_ = node.GetScreenId();
displayHasSecSurface_.emplace(currentVisitDisplay_, false);
sptr<RSScreenManager> screenManager = CreateOrGetScreenManager();
if (!screenManager) {
RS_LOGE("PrepareScreenRenderNode ScreenManager is nullptr");
return;
}
node.SetScreenInfo(screenManager->QueryScreenInfo(node.GetScreenId()));
ScreenInfo curScreenInfo = screenManager->QueryScreenInfo(node.GetScreenId());
offsetX_ = curScreenInfo.offsetX;
offsetY_ = curScreenInfo.offsetY;
UpdateScreenNodeCompositeType(node, curScreenInfo);
ResetSurfaceNodeAttrsInScreenNode(node);
curScreenNode_ = node.shared_from_this()->ReinterpretCastTo<RSScreenRenderNode>();
/* 此处直接获取 Frame 的宽高作为逻辑分辨率,缺失了对屏幕旋转状态的校验 */
int32_t logicalScreenWidth = static_cast<int32_t>(node.GetRenderProperties().GetFrameWidth());
int32_t logicalScreenHeight = static_cast<int32_t>(node.GetRenderProperties().GetFrameHeight());
if (logicalScreenWidth <= 0 || logicalScreenHeight <= 0) {
logicalScreenWidth = static_cast<int32_t>(curScreenInfo.width);
logicalScreenHeight = static_cast<int32_t>(curScreenInfo.height);
}
...
/* 创建画布后已经和物理宽高一致,导致buffer宽高与物理不一致。 */
CreateCanvas(logicalScreenWidth, logicalScreenHeight);
...
}
2、屏幕被裁剪成正方形:由于buffer的宽高已经发生错乱,导致srcRect和dstRect 计算错误:
graphic/graphic_2d/rosen/modules/render_service_base/src/pipeline/rs_surface_render_node.cpp
cpp
void RSSurfaceRenderNode::PrepareRenderBeforeChildren(RSPaintFilterCanvas& canvas)
{
auto deviceClipRect = canvas.GetDeviceClipBounds();
UpdateSrcRect(canvas, deviceClipRect);
RectI dstRect = { deviceClipRect.GetLeft() + offsetX_, deviceClipRect.GetTop() + offsetY_,
deviceClipRect.GetWidth(), deviceClipRect.GetHeight() };
}
void RSSurfaceRenderNode::UpdateSrcRect(const Drawing::Canvas& canvas, const Drawing::RectI& dstRect,
bool hasRotation)
{
...
auto localClipRect = RSPaintFilterCanvas::GetLocalClipBounds(canvas, &dstRect).value_or(Drawing::Rect());
const RSProperties& properties = GetRenderProperties();
/* 下面就是由于 比较都会被设为高度(默认为横屏情况)*/
int left = std::clamp<int>(localClipRect.GetLeft(), 0, properties.GetBoundsWidth());
int top = std::clamp<int>(localClipRect.GetTop(), 0, properties.GetBoundsHeight());
int width = std::clamp<int>(std::ceil(localClipRect.GetWidth() - RECT_CEIL_DEVIATION), 0,
std::ceil(properties.GetBoundsWidth() - left));
int height = std::clamp<int>(std::ceil(localClipRect.GetHeight() - RECT_CEIL_DEVIATION), 0,
std::ceil(properties.GetBoundsHeight() - top));
RectI srcRect = {left, top, width, height};
SetSrcRect(srcRect);
...
}
}
故导致buffer被裁剪成正方形!
解决方式
1、针对旋转问题:
rosen/modules/render_service/core/pipeline/rs_processor.cpp
cpp
@@ -105,8 +106,21 @@ bool RSProcessor::Init(RSScreenRenderNode& node, int32_t offsetX, int32_t offset
mirroredId_ = mirroredId;
screenInfo_ = screenManager->QueryScreenInfo(node.GetScreenId());
- auto mirrorNode = node.GetMirrorSource().lock();
- CalculateScreenTransformMatrix(mirrorNode ? *mirrorNode : node);
+ auto children = node.GetChildrenList();
+ if (!children.empty()) {
+ std::shared_ptr<RSLogicalDisplayRenderNode> displayNode = nullptr;
+ for (const auto& child : children) {
+ if (auto node = child.lock()) {
+ displayNode = node->ReinterpretCastTo<RSLogicalDisplayRenderNode>();
+ break;
+ }
+ }
+ if (displayNode) {
+ screenInfo_.rotation = displayNode->GetRotation();
+ auto mirrorNode = displayNode->GetMirrorSource().lock();
+ CalculateScreenTransformMatrix(mirrorNode ? *mirrorNode : *displayNode);
+ }
+ }
2、针对裁剪问题:
main_thread/rs_render_service_visitor.cpp
cpp
@@ -65,8 +65,9 @@ void RSRenderServiceVisitor::PrepareScreenRenderNode(RSScreenRenderNode& node)
RS_LOGE("PrepareScreenRenderNode ScreenManager is nullptr");
return;
}
- node.SetScreenInfo(screenManager->QueryScreenInfo(node.GetScreenId()));
+
ScreenInfo curScreenInfo = screenManager->QueryScreenInfo(node.GetScreenId());
+ node.SetScreenInfo(curScreenInfo);
offsetX_ = curScreenInfo.offsetX;
offsetY_ = curScreenInfo.offsetY;
UpdateScreenNodeCompositeType(node, curScreenInfo);
@@ -74,15 +75,32 @@ void RSRenderServiceVisitor::PrepareScreenRenderNode(RSScreenRenderNode& node)
ResetSurfaceNodeAttrsInScreenNode(node);
curScreenNode_ = node.shared_from_this()->ReinterpretCastTo<RSScreenRenderNode>();
+ auto& boundsGeoPtr = (node.GetRenderProperties().GetBoundsGeometry());
+ RSBaseRenderUtil::SetNeedClient(boundsGeoPtr && boundsGeoPtr->IsNeedClientCompose());
+ PrepareChildren(node);
+ node.GetCurAllSurfaces().clear();
+ node.CollectSurface(node.shared_from_this(), node.GetCurAllSurfaces(), false, false);
+}
+void RSRenderServiceVisitor::PrepareLogicalDisplayRenderNode(RSLogicalDisplayRenderNode& node)
+{
+ sptr<RSScreenManager> screenManager = CreateOrGetScreenManager();
+ if (!screenManager) {
+ RS_LOGE("PrepareScreenRenderNode ScreenManager is nullptr");
+ return;
+ }
+ ScreenInfo curScreenInfo = screenManager->QueryScreenInfo(node.GetScreenId());
int32_t logicalScreenWidth = static_cast<int32_t>(node.GetRenderProperties().GetFrameWidth());
int32_t logicalScreenHeight = static_cast<int32_t>(node.GetRenderProperties().GetFrameHeight());
if (logicalScreenWidth <= 0 || logicalScreenHeight <= 0) {
logicalScreenWidth = static_cast<int32_t>(curScreenInfo.width);
logicalScreenHeight = static_cast<int32_t>(curScreenInfo.height);
+ auto rotation = node.GetRotation();
+ if (rotation == ScreenRotation::ROTATION_90 || rotation == ScreenRotation::ROTATION_270) {
+ std::swap(logicalScreenWidth, logicalScreenHeight);
+ }
}
-
- if (node.IsMirrorScreen()) {
+ if (node.IsMirrorDisplay()) {
auto mirrorSource = node.GetMirrorSource();
auto existingSource = mirrorSource.lock();
if (!existingSource) {
@@ -93,18 +111,9 @@ void RSRenderServiceVisitor::PrepareScreenRenderNode(RSScreenRenderNode& node)
CreateCanvas(logicalScreenWidth, logicalScreenHeight, true);
}
PrepareChildren(*existingSource);
- } else {
- auto& boundsGeoPtr = (node.GetRenderProperties().GetBoundsGeometry());
- RSBaseRenderUtil::SetNeedClient(boundsGeoPtr && boundsGeoPtr->IsNeedClientCompose());
- CreateCanvas(logicalScreenWidth, logicalScreenHeight);
- PrepareChildren(node);
+ return;
}
- node.GetCurAllSurfaces().clear();
- node.CollectSurface(node.shared_from_this(), node.GetCurAllSurfaces(), false, false);
-}
-
-void RSRenderServiceVisitor::PrepareLogicalDisplayRenderNode(RSLogicalDisplayRenderNode& node)
-{
+ CreateCanvas(logicalScreenWidth, logicalScreenHeight);
PrepareChildren(node);
}
@@ -139,7 +148,13 @@ void RSRenderServiceVisitor::ProcessScreenRenderNode(RSScreenRenderNode& node)
return;
}
- if (node.IsMirrorScreen()) {
+ ProcessChildren(node);
+ processor_->PostProcess();
+}
+
+void RSRenderServiceVisitor::ProcessLogicalDisplayRenderNode(RSLogicalDisplayRenderNode& node)
+{
+ if (node.IsMirrorDisplay()) {
auto mirrorSource = node.GetMirrorSource();
auto existingSource = mirrorSource.lock();
if (!existingSource) {
@@ -156,12 +171,7 @@ void RSRenderServiceVisitor::ProcessScreenRenderNode(RSScreenRenderNode& node)
} else {
ProcessChildren(node);
}
- processor_->PostProcess();
-}
-
-void RSRenderServiceVisitor::ProcessLogicalDisplayRenderNode(RSLogicalDisplayRenderNode& node)
-{
- ProcessChildren(node);
+
for (auto& [_, funcs] : foregroundSurfaces_) {
for (const auto& func : funcs) {
func();
主要是旋转值从node获取,并且对逻辑宽高重新修改,对画布canvas创建大小问题就可以解决。