《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, thatwill 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移植如何实现这些部分并包含哪些不同之处。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

成熟的内外网数据交换方案,如何实现跨网传输?

网络迅速发展&#xff0c;我们可以从网络上查找到各式各样的信息&#xff0c;但是同时网络安全问题也随之严重。近几年&#xff0c;各种有关网络安全的新闻不断被报道&#xff0c;数据泄露给很多企业带来了严重打击&#xff0c;不仅是经济损失&#xff0c;严重者还会对企业的声…

Go 基本数据

第 2 章 基本数据类型 Go 的数值类型包括了不同大小的整数 、浮点数 、复数&#xff1b; 各种数值类型分别有自己的大小&#xff0c;对正负号支持也各不相同&#xff1b; 1. 整数&#xff08;OK&#xff09; 整数类型&#xff08;整型&#xff09;整数类型Go 语言同时支持 有…

Servlet 与 MVC

主要内容 Servlet 重点 MVC 重点 Filter 重点 章节目标 掌握 Servlet 的作用 掌握 Servlet 的生命周期 掌握 JSP 的本质 掌握 MVC 的设计思想 掌握 Filter 的作用及使用场景 第一节 Servlet 1. Servlet 概念 Servlet 是在服务器上运行的能够对客户端请求进行处理&a…

Parallels Desktop 18 for Mac(pd虚拟机) 激活版

Parallels Desktop 18是一款功能强大的虚拟机软件&#xff0c;可以在Mac操作系统上同时运行多种操作系统&#xff0c;包括Windows、Linux、Android等。该软件提供了多种高级功能&#xff0c;如支持DirectX 11游戏、3D图形和OpenGL应用程序&#xff0c;以及运行Windows和Mac应用…

Mysql数据库DQL查询语言之表连接(联合查询)

表连接 关系字段&#xff1a;两表中有关联关系的字段 \关系字段&#xff1a;两表之间存在关系的字段 什么是表连接&#xff1f; 当我们的查询结果需要从多张表中获取时&#xff0c;此时应该让表之间建立连接&#xff0c;同时获取数据 内连接 特点&#xff1a;同时对连接双方做…

[BUUCTF]-PWN:babyfengshui_33c3_2016解析

又是一道堆题&#xff0c;先看保护 关键信息是32位&#xff0c;没开pie 直接看ida 大致是alloc创建堆块&#xff0c;free释放堆块&#xff0c;show查看堆块内容&#xff0c;fill填充堆块内容 其他的都没啥关键的要讲&#xff0c;但alloc那里非常需要解析一下 解释如上图 再具…

做外贸指定货代,想不到的麻烦

最近在外贸群里看到小伙伴们对指定货代的吐槽以及自己遇到的糟心事&#xff0c;写下来&#xff0c;也为我们今后遇到客户指定货代的时候提个醒。 小伙伴A说&#xff0c;因为客户设计的包装有问题&#xff0c;被海关查验&#xff0c;然后客户的指定货代要求小伙伴支付高于货值的…

向量库与嵌入模型

简介 非结构化数据 世界上大约超过百分之八十的数据都是非结构化数据&#xff0c;例如&#xff1a;图像、音视频、自然语言等&#xff0c;这些模型不遵循预定义的模式或组织方式&#xff0c;可以使用各种人工智能 (AI) 和机器学习 (ML) 模型转换为向量。 嵌入向量&#xff0…

用ChatGPT教学、科研!大学与OpenAI合作

亚利桑那州立大学&#xff08;简称“ASU”&#xff09;在官网宣布与OpenAI达成技术合作。从2024年2月份开始&#xff0c;为所有学生提供ChatGPT企业版访问权限&#xff0c;主要用于学习、课程作业和学术研究等。 为了帮助学生更好地学习ChatGPT和大语言模型产品&#xff0c;AS…

01.Elasticsearch应用(一)

Elasticsearch应用&#xff08;一&#xff09; 1.什么是ELK ELK是一个免费开源的日志分析架构技术栈总称&#xff0c;包含三大基础组件&#xff0c;分别是Elasticsearch、Logstash、Kibana。但实际上ELK不仅仅适用于日志分析&#xff0c;它还可以支持其它任何数据搜索、分析和…

nodejs学习计划--(六)包管理工具

包管理工具 1. 介绍 包是什么 『包』英文单词是 package &#xff0c;代表了一组特定功能的源码集合包管理工具 管理『包』的应用软件&#xff0c;可以对「包」进行 下载安装 &#xff0c; 更新 &#xff0c; 删除 &#xff0c; 上传 等操作 借助包管理工具&#xff0c;可以快…

【若依】前后端分离框架部署

1.拉取若依项目代码 进入若依 基于SpringBootVue前后端分离的Java快速开发框架&#xff0c;并通过相应协议拉取到本地IDE 2.前端部署 2.1.下载nodejs 进入nodejs官网下载所需版本&#xff0c; 完成后在命令行运行npm -v可查询版本 2.2.配置依赖 在若依ui目录下运行 np…

oracle古法unwrap手艺(oracle存储过程解码)

先说骚话 首先oracle官方是不支持解包的&#xff0c;见Doc ID 376303.1 但是需求来了。我就寄希望于民间大神的工具。很顺利&#xff0c;找到了几个&#xff0c;甚至还有网页版&#xff0c;以为是个easy money。 但是&#xff0c;我点背&#xff0c;总是能遇到精彩的情况。数…

Android开发--状态栏布局隐藏的方法

1.问题如下&#xff0c;安卓布局很不协调 2.先将ActionBar设置为NoActionBar 先打开styles.xml 3.使用工具类 package com.afison.newfault.utils;import android.annotation.TargetApi; import android.app.Activity; import android.content.Context; import android.graph…

【Elasticsearch篇】详解使用RestClient操作索引库的相关操作

文章目录 &#x1f354;什么是Elasticsearch&#x1f33a;什么是RestClient&#x1f386;代码操作⭐初始化RestClient⭐使用RestClient操作索引库⭐使用RestClient删除索引库⭐使用RestClient判断索引库是否存在 &#x1f354;什么是Elasticsearch Elasticsearch是一个开源的分…

SpringBoot 统计更多Api接口SQL相关日志信息

统计(查询,更新,批量更新)SQL执行次数及用时并输出log import com.zhangziwa.practisesvr.utils.log.LogContext; import org.apache.ibatis.executor.statement.StatementHandler; import org.apache.ibatis.plugin.Interceptor; import org.apache.ibatis.plugin.Intercepts…

什么是通配监听端口? 什么是通配监听IP?

什么是通配监听端口? 监听端口&#xff1a; 指的是服务器或服务开启的特定TCP或UDP端口号&#xff0c;等待客户端连接或发送数据。TCP/IP协议下每个端口只能由一个服务独占监听&#xff0c;一个服务或应用会指定监听特定的一个或多个端口来接收客户端的连接请求。 例如 Web…

RocketMQ-Windows版本安装

RocketMQ-Windows版本安装 1.环境准备 JDK和maven需要先安装好&#xff0c;我这里使用的JDK1.8版本 Maven 3.8.6版本。需要注意的是&#xff0c;这里配置java时需要指定JAVA_HOME环境变量 RokectMQ才能正常启动。 2.下载RocketMQ 官网下载: https://rocketmq.apache.org/z…

C++读取txt文件中的逐个字符

为了增加读取的灵活性&#xff0c;所以separator和filename都设置为在主函数中获取输入或者在函数中传参的视线方法 举个例子&#xff0c;txt文件如下&#xff1a; household;2;true; 首先声明一个读取数据的文件 void read_data_file(const string& filename,char se…

Matplotlib Mastery: 从基础到高级的数据可视化指南【第30篇—python:数据可视化】

文章目录 Matplotlib: 强大的数据可视化工具1. 基础1.1 安装Matplotlib1.2 创建第一个简单的图表1.3 图表的基本组件&#xff1a;标题、轴标签、图例 2. 常见图表类型2.1 折线图2.2 散点图2.3 条形图2.4 直方图 3. 图表样式与定制3.1 颜色、线型、标记的定制3.2 背景样式与颜色…