65

爱奇艺自研 UI 引擎渲染技术分析

 5 years ago
source link: https://mp.weixin.qq.com/s/qgkX74Sglz1n1zZxmpdlzg?amp%3Butm_medium=referral
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

点击上方 开发者技术前线 ”, 选择“星标”

13点21分打卡 就是真爱

来源:爱奇艺技术产品团队 | 本期 责编:可可   

摘要

我们都知道,好的视频内容可以吸引更多用户。那么在好的内容基础上,我们希望用更好的架构及渲染技术,不断迭代出更轻、更炫、更平滑的客户端,保证用户有更好的体验。在此驱动下我们致力于开发一套高效的跨平台渲染引擎Lyra,为用户提供新的体验。本文主要详细阐述在PC客户端上引入的新渲染技术。

爱奇艺PC客户端之前使用的UI引擎是公司内部开发的QuiLib。QuiLib是基于开源的uilib和DuiLib开发的轻量级的UI引擎。QuiLib使用了DirectUI框架,其主要思想就是控件无窗口化。虽然在很长一段时间内,QuiLib都发挥着至关重要的作用,但是随着渲染技术和计算机技术的发展,QuiLib暴露了它的很多缺点。

m6VRnuN.png!web

QuiLib的渲染的流程

QuiLib的动画Timer、业务逻辑、布局、渲染等均在主线程,这样每一个阶段的耗时都会导致整个流程的推迟或卡顿,其主要问题有:

(1)绘制性能差,如当UI元素进行alpha或者旋转变化时,paint慢且需要多次内存拷贝,效率很低;

(2)冗余layout,排版效率低,一次业务处理过程中若对某个节点多次操作,会导致该节点冗余layout;

(3)动画不流畅,每组动画都有独立的时间线,同时主线程负载太重,任何一环耗时,都会导致动画不平滑,用户体验差。

其次,在组件架构层面,QuiLib也存在一些欠缺。

JvQBZn6.png!web

组件架构图

从组件架构图可以看出:QuiLib基于Windows和GDI图形库;QuiLib 没有利用D3D等3D图形技术来给UI渲染提速,并且重度使用了GDI,无法做到渲染跨平台化。这样会导致如下问题:不能充分利用显卡的性能,不支持跨平台化。

技术引入

为了解决现在的框架(即Quilib)具有的以上问题,我们做出了以下的技术解决方案:

(1)3D渲染:充分利用显卡性能,加速图形渲染速度; 

(2)异步渲染:把渲染流程细划为业务逻辑、样式变化、布局、生成渲染命令、执行渲染命令、合成渲染层和刷新到屏幕几个阶段;每个线程使用一个唯一的动画时间线,来驱动动画;

(3)分层渲染:根据情况,自动把某些频繁渲染的元素从主渲染层提升为单独的渲染层,这样每个层都进行单独的渲染流程,最后再把这些渲染结果合成并且上传到屏幕;

引入新的设计思想和渲染技术,能够让基于Lyra开发的PC应用运行更平滑,达到和mac系统上应用一样的平滑度。

技术实践

为了实践以上设计思想和渲染技术,我们开发了一个新的UI渲染引擎并且命名为Lyra(天琴座),寓意希望新的UI渲染引擎像天琴座一样灿烂。

跨平台和GPU渲染图形库

Lyra一开始就致力于跨平台和GPU加速渲染。通过调研和比较现在流行的图形库及游戏渲染引擎,Lyra最终选择了使用skia。

VNRNF3A.png!web

Lyra引擎组件架构图:阐述了新UI引擎的层级关系

skia具有如下这些优点:

(1)跨平台;

(2)高效基本图元渲染;

(3)高效的字体处理及文本渲染;

(4)丰富的图像格式支持;

(5)支持3D渲染,可以无缝切换为2D渲染。

得益于skia 3D & 2D backend的无缝切换,lyra可以针对不同的机器配置选择不同的渲染方式,优化Layered窗口这种需要渲染后处理的特殊情况,支持运行时渲染方式的自动fallback。也正是3D & 2D backend的无缝切换也导致skia资源占用很高,为了优化资源占用及命令序列化,也需要做很多侵占式的定制,在此不详述了。

异步渲染

Lyra使用了多线程渲染技术:UI主线程主要负责与用户交互,Render线程主要负责图形渲染。

IvMji2Y.png!web

Lyra新的渲染流程图

如上图:Lyra把渲染流程细分为更多的步骤:Event&Message、样式变化、Layout、Paint(生成绘制命令)、Execute(执行绘制命令)、合成、刷新到窗口。在渲染过程中,比较耗时的几个点就是用户逻辑处理、Layout和执行渲染命令、合成。

Lyra把Paint以及其之前和Execute以及其之后分为两大块,这两大块是并行运行。这样的好处是:执行渲染命令的耗时不会导致用户响应延迟,主线程的Timer等比较耗时的逻辑也不会导致渲染延迟;同时形成渲染流水,执行灵活的帧选择策略,最大化渲染效率,提高响应速度。

动画系统由基于线程的唯一Timer来驱动,保证一个线程一个时间线,这样减少了Timer资源的消耗,提高了动画的渲染效率。同时将动画分为主线程动画和render线程动画,主线程动画操作逻辑渲染节点,Render线程动画驱动layer层相关动画。动画系统自动将不同的动画附着到不同的线程。通过如此设计可以支持3D动效、复杂动效,各部件联动,最大化动画帧率。

分层渲染

我们知道一个UI程序,大部分时候只有个别元素在响应事件。比如旋转时,理论上我们只需要绘制正在旋转的这个元素就可以。所以基于这种理念,Lyra实现了分层渲染技术,针对于每个元素,Lyra内部会根据情况创建新层或者销毁多余的层。

分层渲染,需要解决以下问题:各种树之间的逻辑关系;何时创建新的层。

我们用一个示例来说明分层技术的实现原理。

只有主层

在这个示例中,UI第一次展示时,只有主层,如下图所示:

3aIbiaQ.png!web

创建分层渲染中的所有树:

(1)解析xml生成一棵Control树,这棵树主要负责处理事件和消息,以及管理各个Control的生命周期;

(2)生成一棵RenderObject树,这棵树的RenderObject和Control树中的Control有一一映射关系,并且RenderObject生命周期的管理完全由Control负责;

(3)Lyra根据需要会生成一棵RenderLayer树,同时也会生成一棵GraphicsLayer树;GraphicsLayer树上的结点和RenderLayer树上的结点有一一映射关系。

构建新层

当用户旋转其中一个元素时,就需要创建新的层。旋转C-5时,树之间的关系以及层之间关系就有如下图新的变化:

6Zn6JrI.png!web

这里Lyra根据需要会生成新的层RL-Rotation(对应于RO-5)和RL-Fake(对应于RO-6)。

异步绘制

示例中的3层在UI主线程生成绘制命令,并且交换到Render线程,下图展示了异步绘制:

EjYveyi.png!web

RenderLayer树来负责驱动关联于它上的RenderObject的Paint,生成绘制命令。 GraphicsLayer对应于真正的LyraSurface,会驱动RenderLayer生成绘制命令,并且把绘制命令交换到渲染线程。

渲染线程在接收到绘制命令后,填充屏幕像素,如下图所示:

267VvuF.png!web

Lyra合成器会驱动GraphicsLayer在渲染线程中执行绘制命令,并且合成绘制结果,最后刷新到屏幕上。

本文主要简述了Lyra渲染技术相关的一些突破性工作:

(1)3D渲染、跨平台渲染;

(2)异步渲染,基于线程Timer驱动的动画系统;

(3)分层渲染。如果你想深入了解或者使用Lyra,可以直接在公众号上留言。

开发者技术前线 ,汇集技术前线快讯和关注行业趋势,大厂干货,是开发者经历和成长的优秀指南。

喜欢就点个好看吧!


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK