《WebKit 技术内幕》学习之八(1):硬件加速机制

《WebKit 技术内幕》之八(1):硬件加速机制

1 硬件加速基础

1.1 概念

        这里说的硬件加速技术是指使用GPU的硬件能力来帮助渲染网页,因为GPU的作用主要是用来绘制3D图形并且性能特别好,这是它的专长所在,它同软件渲染有很多不同的地方,既有自己的优点,当然也有些不足之处。

        对于GPU绘图而言,通常不像软件渲染那样只是计算其中更新的区域,一旦有更新请求,如果没有分层,引擎可能需要重新绘制所有的区域,因为计算更新部分对GPU来说可能耗费更多的时间。当网页分层之后,部分区域的更新可能只在网页的一层或者几层,而不需要将整个网页都重新绘制。通过重新绘制网页的一个或者几个层,并将它们和其他之前绘制完的层合成起来,既能使用GPU的能力,又能够减少重绘的开销。

        之前,笔者总是将RenderLayer对象和最终显示出来的图形层次一一对应起来,也就是每个RenderLayer对象都有一个后端存储与其对应,这样有很多好处,那就是当每一层更新的时候,WebKit只需要更新RenderLayer对象包含的节点即可。所以当某一层有任何更新时候,WebKit重绘该层的所有内容(当然对于Tiledlayer不是这样的情况)。这是理想情况,在现实中不一定会这样,主要原因是实际中的硬件能力和资源有限。为了节省GPU的内存资源,硬件加速机制在RenderLayer树建立之后需要做三件事情来完成网页的渲染。

  • WebKit决定将哪些RenderLayer对象组合在一起,形成一个有后端存储的新层,这一新层不久后会用于之后的合成(Compositing),这里称之为合成层(Compositing Layer)。每个新层都有一个或者多个后端存储,这里的后端存储可能是GPU的内存。对于一个RenderLayer对象,如果它没有后端存储的新层,那么就使用它的父亲所使用的合成层。
  • 将每个合成层包含的这些RenderLayer内容绘制在合成层的后端存储中,如第7章所述,这里的绘制可以是软件绘制也可以是硬件绘制。
  • 由合成器(Compositor)将多个合成层合成起来,形成网页的最终可视化结果,实际就是一张图片。合成器是一种能够将多个合成层按照这些层的前后顺序、合成层的3D变形等设置而合成一个图像结果的设施,后面会介绍Chromium合成器的工作原理。

        在WebKit中,只有把编译的C代码宏(macro)“ACCELERATED_COMPOSITING”打开之后,硬件加速机制才会被开启,有关硬件加速的基础设施才会被编译进去。

1.2 WebKit硬件加速设施

        一个RenderLayer对象如果需要后端存储,它会创建一个RenderLayerBacking对象,该对象负责Renderlayer对象所需要的各种存储。正如前面所述,理想情况下,每个RenderLayer都可以创建自己的后端存储,但事实上不是所有RenderLayer都有自己的RenderLayerBacking对象。如果一个RenderLayer对象被WebKit依照一定的规则创建了后端存储,那么该RenderLayer被称为合成层。

        每个合成层都有一个RenderLayerBacking ,RenderLayerBacking负责管理RenderLayer所需要的所有后端存储,因为后端存储可能需要多个存储空间。在WebKit中,存储空间使用GraphicsLayer类来表示,下图描述了这些主要类和它们的关系。

                               图WebKit的硬件加速基础类

        上图的上半部分是WebKit项目中WebCore部分的四个基础类,RenderLayer和RenderLayerBacking已经做过一些介绍了,GraphicsLayer表示RenderLayer中前景层、背景层所需要的一个后端存储。每个GraphicsLayer都使用一个GraphicsLayerClient对象,该对象能够收到GraphicsLayer的一些状态更新信息,并且包含一个绘制该GraphicsLayer对象的方法,RenderLayerBacking继承于该类。GraphicsLayer是WebKit中的基础类,主要定义一套标准接口,在WebKit不同的移植中,它们有不同的子类及其实现,图8-1的下半部分是两个不同移植的具体实现类。

        哪些RenderLayer对象可以是合成层呢?如果一个RenderLayer对象具有以下的特征之一,那么它就是合成层。

  • RenderLayer具有CSS 3D属性或者CSS透视效果。
  • RenderLayer包含的RenderObject节点表示的是使用硬件加速的视频解码技术的HTML5“video”元素。
  • RenderLayer包含的RenderObject节点表示的是使用硬件加速的Canvas 2D元素或者WebGL技术。
  • RenderLayer使用了CSS透明效果的动画或者CSS变换的动画。
  • RenderLayer使用了硬件加速的CSS Filters技术。
  • RenderLayer使用了剪裁(Clip)或者反射(Reflection)属性,并且它的后代中包括一个合成层。
  • RenderLayer有一个Z坐标比自己小的兄弟节点,且该节点是一个合成层。

        至于为什么这么做,有以下三个原因:首先当然是合并一些RenderLayer层,这样可以减少内存的使用量;其二是在合并之后,尽量减少合并带来的重绘性能和处理上的困难;其三对于那些使用单独层能够显著提升性能的RenderLayer对象,可以继续使用这些好处,例如使用WebGL技术的canvas元素。

        下图描述了RenderLayer树、RenderLayerBacking对象和GraphicsLayer树这些硬件加速基础设施的对应关系。RenderLayer树中的第四个节点没有创建RenderLayerBacking对象,因为不符合上面的创建条件,而对于每个RenderLayerBacking对象,它也至少需要一个GraphicsLayer对象,当然也可能需要多个,图中的RenderLayerBacking对象分别需要2个、1个和4个GraphicsLayer对象,这些对象分别表示什么呢?图8-3描述了一个RenderLayerBacking对象可能包括的众多GraphicsLayer对象层,它们表示不同的含义。

                          图RenderLayer树、RenderLayerBacking对象和GraphicsLayer树

                                图RenderLayerBacking包含的各种GraphicsLayer对象层

        为什么一个RenderLayerBacking对象需要这么多层呢?原因有很多,例如WebKit需要将滚动条独立开来称为一个层,需要两个容器层来表示RenderLayer对应的Z坐标为正数的子女和Z坐标为负数的子女,需要滚动的内容建立新层,还可能需要剪裁层和反射层。那么这些层是如何被组织并且它们被绘制的顺序是如何呢?上图中的树状结构描述了所有层的绘制顺序,按照先根顺序遍历的结果即是绘制顺序,图中每个层就是一个GraphicsLayer对象。对于某个RenderLayerBacking对象来说,其主层是肯定存在的,其他层则不一定存在,因为不是每个RenderLayer对象都需要用到它们。

                                图RenderLayerBacking中包含的GraphicsLayer对象

管理这些合成层等工作的是RenderLayerCompositor类,这个类可以说是个“大管家”。它不仅计算和决定哪些RenderLayer对象是合成层,而且为合成层创建GraphicsLayer对象,如图8-5所示。每个RenderView对象包含一个RenderLayerCompositor,这些对象仅在硬件加速机制下才会被创建。RenderLayerCompositor类本身也类似于一个RenderLayerBacking类,也就是说它也包含一些GraphicsLayer对象,这些对象对应的是整个网页所需要的后端存储。

                                                图RenderLayerCompositor类

1.3 硬件渲染过程

介绍完硬件加速机制所使用的内部设施之后,同前面介绍的软件渲染机制一样,下面详细分析硬件渲染机制过程。渲染的一般过程,在本章最开始的时候已经描述过,这里主要介绍WebKit是如何具体实现这一过程的。

示例代码8-1给出了一个网页,该网页中使用了很多HTML5新功能,它必须使用硬件加速机制才能够渲染,因为这其中的CSS 3D变形、WebGL和Video等都是HTML5引入的新特性,这些新特性必须依赖GPU硬件加速才能达到比较好的效果。

示例代码8-1需要硬件加速机制的HTML5网页

    <html>
      <style>
        div{
          -webkit-transform:rotateY(10deg);
        }
        </style>
        <body>
        <p>test text</p>
        <div>css 3d transform</div>
        <canvas id="webgl"width="80"height="80"></canvas>
        <video width="400"height="300"controls="controls">
          <source src="test.ogg"type="video/ogg">
        </video>
        <script type="text/javascript">
          var canvas=document.getElementById("webgl");
          var gl=canvas.getContext("experimental-webgl");
          gl.clearColor(0.0, 1.0, 0.0, 1.0);
          gl.clear(gl.COLOR_BUFFER_BIT);
        </script>
      </body>
    </html>

        首先看WebKit是如何确定并计算合成层的,图8-6描述了WebKit如何决定哪些层是合成层并为它们分配后端存储的过程。图中主要包含两个部分,都是RenderLayerCompositor类的函数,一是检查RenderLayer对象是否为合成层,如果是的话,为它们创建后端存储对象RenderLayerBacking;二是根据重新更新的合成层来更改合成层树,并修改后端存储对象的一个设置信息。

                                        图WebKit决定合成层并构建合成层树

        除了上图之外,当RenderLayer对象被创建时,网页还有一些其他情况也可能需要创建RenderLayerBacking对象。具体的过程是由RenderLayerModelObject::styleDidChanged()函数调用RenderLayer::styleChanged()函数来触发,然后WebKit调用RenderLayerCompositor::updateLayerCompositingState()函数为RenderLayerModelObject对象所在的RenderLayer层来创建后端存储对象。

        下图主要描述的是WebKit为示例代码8-1建立的合成层和合成层相应的RenderLayerBacking对象。根据前面的解释,WebKit为网页中的5个DOM节点创建RenderLayer对象,分别为HTMLDocument对象、HTMLHtmlElement对象、HTMLDivElement对象、HTMLCanvas对象和HTMLVideo对象。但是,图中只有4个RenderLayerBacking对象,这是因为HTMLHtmlElment对象对应的RenderLayer没有自己的RenderLayerBacking对象,原因是该RenderLayer对象不满足之前所描述的规则。

                            图示例代码的RenderLayer树和RenderLayerBacking对象

        其次,WebKit需要遍历和绘制每一个合成层,也就是每个合成层可能有一个或者多个RenderLayer对象,这可能包含至少四种情形,第一种情形是HTMLDocument节点,WebKit绘制该节点所在的合成层需要遍历两个RenderLayer对象所包含的子树,与其他绘制的内容的调用过程非常相似,该合成层也需要一个用于2D图形的图形上下文对象,该对象的内部实现由各个移植来决定,具体的2D绘图在后面介绍。该层的调用过程如图8-8所示,该过程同软件渲染非常类似,只是递归过程稍微不同。

                                图绘制HTMLDocument对应的RenderLayer层

        在软件渲染过程中,paintLayer函数被递归调用,也就是从RenderLayer根节点开始,直到所有的RenderLayer对象都被遍历为止。在硬件加速机制中,情况有所不同,这是因为引入了合成层的概念,每个RenderLayer对象被绘制到祖先链中最近的合成层。示例代码是WebKit中RenderLayer::paintLayer()函数的条件判断部分的代码,用来检查是否在父节点所在的后端存储中绘制当前节点。如果它不是合成层,那么就继续绘制该层;如果它是的话,那么就直接返回。在之后的逻辑中,WebKit会重新为每一个合成层调用绘制操作,每个合成层的图形上下文都不一样,这点不像软件渲染过程。

        示例代码WebKit的RenderLayer::paintLayer()函数的条件判断

    RenderLayer::paintLayer(){
        if (isComposited()){
            if (context->updatingControlTints()||(paintingInfo.paintBehavior&
                                   PaintBehaviorFlattenCompositingLayers)){
                paintFlags|=PaintLayerTemporaryClipRects;
            }else if (!backing()->paintsIntoWindow()
                &&!backing()->paintsIntoCompositedAncestor()
                &&!shouldDoSoftwarePaint(this, paintFlags&
    PaintLayerPaintingReflection)){
          //If this RenderLayer should paint into its backing, that
    will be done via RenderLayerBacking::paintIntoLayer().
          return;
         }
        }else if (viewportConstrainedNotCompositedReason()==
    NotCompositedForBoundsOutOfView){
         return;
       }
    }

        第二种情形是使用CSS 3D变形的合成层,这在本章8.3.3节中介绍。第三种情形是使用WebGL技术的Canvas元素所在的合成层,它的绘制是由JavaScript操作来完成的,并且使用了3D的图形上下文,后面会在8.3.1节中介绍。第四种情形是类似使用了硬件加速的视频元素所在的合成层,该层的内容其实是由视频解码器来绘制,而后通过定时器或者其他通知机制来告诉WebKit该层内容已经发生变化,需要重新合成,这在后面的章节中介绍。

        最后一个步骤是渲染引擎将所有绘制完的合成层合成起来,这个是由WebKit的移植来完成的,在本章的8.2.3小节中将做详细的介绍。

1.4 3D图形上下文

        WebKit中的3D图形上下文主要是提供一组抽象接口,这组接口能够提供类似OpenGLES(使用GPU硬件能力的3D图形应用编程接口)的功能,其主要目的当然也是使用OpenGL绘制3D图形的能力。这一层抽象能够将WebKit各个移植的不同部分隐藏起来,WebCore只是使用统一的抽象接口。在WebKit中,3D图形上下文的主要用途是WebGL,当然启用硬件加速的Canvas2D等HTML5技术也会使用3D图形技术,不过情况有些不同。

        下图给出了WebKit的GraphicsContext3D类,该类是一个抽象类,其包含的接口所处理的对象就是OpenGL中所提供的能力,例如针对纹理、着色器、纹理贴图、顶点等GL操作,不过这里是一个C++类的封装而已。

                                图WebKit的3D图形上下文相关类

        上图中的GraphicsContext3DPrivate就是一个跟WebKit的各个移植相关的类,虽然在各个移植中都是使用该名称,但是每个移植的定义非常不同,它主要是针对移植的不同来实现的。PlatformGraphicsContext3D类是WebCore用于创建Surface等对象的参数,所以其名字是一致的,但是每个移植的定义实际上不一样。

        GraphicsContext3D中的接口有三种类型,第一类是所有移植共享实现的接口,例如texImage2DResourceSafe;第二类是一些移植能够共享实现的接口,例如texImage2D,它们可以直接调用OpenGL或者OpenGL ES的应用编程接口;第三类则是跟每个移植具体相关,例如platformGraphicsContext3D。

        这些跟移植相关的类都是需要每个移植去实现的,否则这一机制不能工作,下面的部分就是Chromium移植如何实现这些部分并包含哪些不同之处。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/340827.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

现代密码学基础(2)

目录 一. 介绍 二. 举例&#xff1a;移位密码 &#xff08;1&#xff09;密文概率 &#xff08;2&#xff09;明文概率 三. 举例&#xff1a;多字母的移位密码 四. 完美安全 五. 举例&#xff1a;双子母的移位密码 六. 从密文角度看完美安全 七. 完美保密性质 一. 介绍…

2024年【陕西省安全员B证】免费试题及陕西省安全员B证复审考试

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 2024年陕西省安全员B证免费试题为正在备考陕西省安全员B证操作证的学员准备的理论考试专题&#xff0c;每个月更新的陕西省安全员B证复审考试祝您顺利通过陕西省安全员B证考试。 1、【多选题】下列关于安全帽&#xf…

盘点几种有线扩展Wifi覆盖范围方式的优缺点

前言 前几天小白到一个朋友的家里&#xff0c;发现她家的主路由是放在玄关的。 这个方式就导致了她家三个卧室的Wifi信号都很弱。 她叫我过去帮忙弄一下网络的问题&#xff0c;这个对于有一点电脑知识的小伙伴来说&#xff0c;基本上不是什么难事&#xff0c;因为每个房间基本…

Windows 下ffmpeg安装及实践

Windows 下ffmpeg安装及实践 背景安装实践其他 背景 最近负责音频文件处理相关的业务&#xff0c;涉及到 ffmpeg 对一些音频文件格式的校验&#xff0c;记录一下安装过程及踩坑过程。 安装 如图1所示&#xff0c;进入官网&#xff0c;在windows下任选一个文件&#xff1a;h…

负债 1092.8 亿美元,苹果成全球负债第二多的科技公司丨 RTE 开发者日报 Vol.131

开发者朋友们大家好&#xff1a; 这里是 「RTE 开发者日报」 &#xff0c;每天和大家一起看新闻、聊八卦。我们的社区编辑团队会整理分享 RTE &#xff08;Real Time Engagement&#xff09; 领域内「有话题的 新闻 」、「有态度的 观点 」、「有意思的 数据 」、「有思考的 文…

【网站项目】基于SSM的271楚师师生健康管理系统

&#x1f64a;作者简介&#xff1a;多年一线开发工作经验&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的项目或者毕业设计。 代码可以私聊博主获取。&#x1f339;赠送计算机毕业设计600个选题excel文件&#xff0c;帮助大学选题。赠送开题报告模板&#xff…

【数据结构】在链队列中你可能忽视的二三事

链队列及其基本操作的C语言实现 导言一、链队列二、链队列的基本操作的实现2.1 链队列的数据类型2.2 链队列的初始化2.2.1 带头结点的链队列的初始化2.2.3 不带头结点的链队列的初始化 2.3 链队列的判空2.3.1 带头结点的链队列的判空2.3.2 不带头结点的链队列的判空 2.4 链队列…

《WebKit 技术内幕》学习之七(4): 渲染基础

4 WebKit软件渲染技术 4.1 软件渲染过程 在很多情况下&#xff0c;也就是没有那些需要硬件加速内容的时候&#xff08;包括但不限于CSS3 3D变形、CSS3 03D变换、WebGL和视频&#xff09;&#xff0c;WebKit可以使用软件渲染技术来完成页面的绘制工作&#xff08;除非读者强行…

电力需求侧管理,缓解电力系统峰值压力

电力需求侧管理和电力负荷管理数字化解决方案 《电力需求侧管理办法&#xff08;征求意见稿&#xff09;》和《电力负荷管理办法&#xff08;征求意见稿&#xff09;》的出台正逢其时&#xff0c;结合了新型电力系统实际问题&#xff0c;为缓解电力供需矛盾提供了政策支持和解…

处理Synology Photos视频不生成缩略图

1、在套件中心新增一个套件 套件位置&#xff1a;矿神群晖SPK套件源DSM7.x by IMNKS.COM 2、安装ffmpeg 3、连接ssh&#xff0c;运行命令 如果没有开启ssh功能&#xff0c;在控制面版 - 终端机和 SNMP 命令如下&#xff1a; sudo -i cp /volume2/\appstore/ffmpeg/bin/ffmpe…

如何自己实现一个Spring Boot Starter

现在很多开源的组件都会提供对应的 springboot-starter 包给我们去用&#xff0c;要做一个 starter 包并不难。参照Spring内置的实现就好了&#xff1a; 1、在工程里引入 starter 打包相关的依赖。 2、在我们工程内建 spring.factories 文件&#xff0c;编写我们配置类的全限类…

JavaScript 学习笔记(WEB APIs Day2)

「写在前面」 本文为 b 站黑马程序员 pink 老师 JavaScript 教程的学习笔记。本着自己学习、分享他人的态度&#xff0c;分享学习笔记&#xff0c;希望能对大家有所帮助。推荐先按顺序阅读往期内容&#xff1a; 1. JavaScript 学习笔记&#xff08;Day1&#xff09; 2. JavaSc…

C# 使用System.Threading.Timer 实现计时器

写在前面 以往一般都是用 System.Timers.Timer 来做计时器&#xff0c;而 System.Threading.Timer 也可以实现计时器功能&#xff0c;并且还可以配置首次执行间隔&#xff0c;在功能上比System.Timers.Timer更加丰富&#xff1b;根据这个特性就可以实现按指定时间间隔对委托进…

Postman如何做接口测试:如何导入 swagger 接口文档

&#x1f525; 交流讨论&#xff1a;欢迎加入我们一起学习&#xff01; &#x1f525; 资源分享&#xff1a;耗时200小时精选的「软件测试」资料包 &#x1f525; 教程推荐&#xff1a;火遍全网的《软件测试》教程 &#x1f4e2;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1…

samba服务搭建,并将共享目录映射到windows

系统版本&#xff1a;centos7 1、centos 安装samba yum -y install samba 2、查看安装信息 rpm -qa |grep samba 3、设置开机自启动 systemctl enable smb.service systemctl enable nmb.service 4、设置samba服务器配置文件 sudo vi /etc/samba/smb.conf 注意&#…

【blender渲染】blender流体模拟基础

各位新年好哇&#xff0c;最近在做demo的时候&#xff0c;为了更好的效果&#xff0c;开始摸索一点离线渲染的东西。像这种后续渲染的处理&#xff0c;由于3ds max是更偏向于建模的dcc&#xff0c;有点不那么好使&#xff08;没有说看不起vray的意思哈&#xff09;。 像在实时…

计算机组成原理 01:计算机的发展历程

计算机的发展历程 导言什么是计算机系统计算机系统 硬件软件因此&#xff0c;计算机性能的好坏取决于“软”、“硬” 件功能的总和。 硬件的发展计算机发展阶段第一代&#xff1a;电子管时代第二代&#xff1a;晶体管时代第三代&#xff1a;中小规模集成电路时代第四代&#x…

算法第二十二天-最大数

最大数 题目要求 解题思路 今天的题目&#xff0c;让我们将一组数字重新组合&#xff0c;构成一个最大的整数。由于构成的整数非常大&#xff0c;所以返回结果需要字符串格式。 分析一下规律&#xff1a; 为了避免用int型或者long型越界&#xff0c;所以我们需要把数字先转换…

独立服务器有哪些优势

建立和维护一个强大的线上网站存在对于个人、企业和组织来说至关重要。而作为构建一个稳定、高效网站的基石之一&#xff0c;服务器的选择变得越来越重要。在服务器的选择中&#xff0c;独立服务器已经成为了许多人首选的方案。 独立服务器究竟有哪些优势呢&#xff1f; 1、稳…

拦截器与过滤器

拦截器&#xff08;Interceptor&#xff09;是一种特殊的组件&#xff0c;它可以在请求处理的过程中对请求和响应进行拦截和处理。拦截器可以在请求到达目标处理器之前、处理器处理请求之后以及视图渲染之前执行特定的操作。拦截器的主要目的是在不修改原有代码的情况下&#x…