浏览器和图形引擎渲染对比

本文受众是专业的图形开发者和前端开发者,从介绍的浏览器渲染引擎开始,逐渐引出和图形引擎的比较,尝试从图形视角探索和理解浏览器的渲染原理。

浏览器引擎

浏览器引擎是浏览器的核心部分,负责解析网页内容(如 HTML、CSS 和 JavaScript)并呈现给用户。各种浏览器可能使用不同的引擎,这导致了不同浏览器之间在渲染页面时可能会有细微的差异。以下是一些主要的浏览器引擎及与其关联的浏览器:

  • IE: Trident

  • WebKit: Safari

  • Blink: Chrome、Opera、Edge

WebKit

以 WebKit 为例,WebKit 是一个开源的 Web 浏览器引擎,它为多种浏览器提供支持,如 Apple 的 Safari 浏览器。它起源于 KDE 项目的 KHTML 和 KJS 库,但后来由 Apple 进一步发展并开源,从而产生了 WebKit。WebKit 代码库主要是用 C++ 编写的,其中包含一些 C 和汇编代码。

主要特点和组件:

  • WebCore: 这是 WebKit 的主要部分,负责渲染 HTML 和 CSS。这基于原先的 KHTML。

  • JavaScriptCore: 负责执行 JavaScript,基于原先的 KJS。

在 WebKit 的成功之后,Google 最初使用 WebKit 为其 Chrome 浏览器提供支持,但后来 Google 选择分叉并创建了自己的引擎,名为 Blink。

时间线

WebCore

WebCore 是 WebKit 浏览器引擎的核心部分,将网页内容转化为用户可以看到和与之互动的视觉表示。

WebCore 是 WebKit 最大的组件,该层实现了大部分 Web API ,最重要的是负责解析 HTML 和 CSS,计算布局,并渲染页面。它处理页面中的所有元素,包括文本、图像、视频、SVG、Canvas、WebGL、动画、音频等。它还实现了 CSS JIT,这是现有的唯一 CSS 即时编译器。

渲染过程

WebCore 的渲染过程涉及多个步骤,从接收原始的 HTML、CSS 和 JavaScript 资源开始,到生成用户在屏幕上看到的最终像素结束。以下是基本的渲染步骤:

  1. 解析(CPU):
  • WebCore 开始通过解析 HTML 生成一个 DOM(Document Object Model)树。
  • CSS 也会被解析,生成一个叫做 CSSOM(CSS Object Model)的结构。CSS 是告诉引擎如何在屏幕上呈现 DOM 树的语言。每个 Web 引擎都使用复杂的机制来遍历 DOM 中的所有内容并应用 CSS 定义的规则。
  1. 合并 DOM 和 CSSOM(CPU): DOM 和 CSSOM 被结合,生成一个渲染树(Render Tree)。这个树只包含实际需要被渲染的元素,不包括例如 display: none 的元素。

  2. 布局(CPU): 布局阶段开始,浏览器确定所有有可视表现的元素在屏幕上的确切位置和大小。每个元素将获得一个确定的屏幕坐标。

  3. 划分图层(CPU): 图层是独立于其他内容进行合成的渲染单位,它的决策是基于布局完成后的信息。图层的创造是为了优化性能。一些特定的 CSS 属性和操作,如动画、3D 变换、视频播放等,如果能在它们自己的图层上运行,通常可以更高效地渲染。

  4. 绘制(CPU+GPU): 绘制阶段开始时,WebCore 会遍历渲染树,并使用 UI 后端层来绘制每个元素的具体像素。

  5. 合成(GPU): 对页面上的元素进行分层,并在合成阶段将它们按正确的顺序合并为一个图层,然后呈现给用户。合成通常是渲染流程的最后一个阶段。在这个阶段,浏览器会处理那些可以被 GPU 直接处理的工作,例如页面的滚动、元素的移动和透明度的变化。因为这些操作不需要重新计算布局或重绘整个页面,所以它们通常会比其他操作更加高效。

绘制和合成

绘制和合成大部分是在 GPU 中进行的,对于我们图形开发者来说,进入到了我们熟悉的语境。

绘制

绘制(Painting)过程可以涉及到调用 GPU API,但这取决于具体的渲染场景和浏览器的优化策略。

在浏览器的渲染流程中,"绘制" 通常指的是将渲染树中的每个元素转换为像素数据的过程。这个过程可能首先在 CPU 上完成,并产生一个位图。然后,这个位图可以被上传到 GPU 并存储为纹理,随后在合成阶段由 GPU 处理。

但是,随着硬件加速绘图技术的普及,越来越多的绘图任务直接在 GPU 上进行,特别是当涉及到复杂的图形效果(如 CSS 滤镜、渐变等)时。在这种情况下,浏览器会直接调用 GPU API(例如 OpenGL 或 DirectX)来进行绘图。

所以,有时浏览器的绘制过程是通过调用 GPU API 来完成的,但并不总是这样。具体情况取决于浏览器的实现、页面的内容以及用户设备的硬件和驱动支持。

UI 后端层则负责与特定平台的图形和 UI 系统进行交互。这样,渲染引擎可以"写一次,到处运行",而不必为每个平台编写特定的绘图代码。UI 后端层为浏览器提供了一个平台无关的方法来绘制其内容,使得浏览器可以跨多个操作系统平台工作,而无需担心每个平台的绘图特定细节。

  • Windows:UI 后端层可能使用 DirectX 进行绘图

  • macOS: Core Graphics、Metal

  • Linux:它可能使用 X11 或 Wayland 等

  • iOS :Core Graphics 和 Metal

  • Android:OpenGL ES 或 Vulkan

绘制过程

当 WebCore 进入绘制阶段并开始遍历渲染树时,其主要目的是将每个可见的渲染对象绘制到屏幕上。以下是在这个阶段中的主要步骤和发生的活动:

  1. 确定绘制顺序: WebCore 会根据渲染树中的层次结构确定绘制的顺序。基本的原则是,先绘制在底部的元素,再绘制在其上方的元素。这确保了层叠上下文和 z-index 的正确处理。

  2. 裁剪和隐藏: 不是渲染树上的所有元素都需要绘制。有些元素可能位于视口之外,或者被其他元素完全遮盖。通过裁剪和优化,WebCore 可以跳过这些元素,从而提高绘制的性能。

  3. 调用平台相关的绘图 API WebCore 本身不直接处理低级的图形操作。相反,它依赖于底层的图形 API(例如 macOS 上的 Core Graphics 或 Windows 上的 Direct2D)来执行实际的绘制。

  4. 背景和边框: 对于每个需要绘制的渲染对象,WebCore 首先绘制背景颜色和背景图片(如果有的话),然后绘制边框。

  5. 文字和图像: 接下来,WebCore 会绘制文本、图像和其他内容。对于文本,它会处理字体、大小、颜色和其他样式。对于图像,它可能还会进行缩放或其他转换。

  6. 子元素绘制: 对于容器元素(例如一个具有子元素的 <div>),WebCore 会递归地遍历其子渲染对象,并对每个子对象重复上述的绘制过程。

  7. 处理透明度和复合效果: 如果渲染对象有透明度、阴影或其他复合效果,WebCore 在绘制时会应用它们。

  8. 处理交互状态: 某些元素可能具有交互状态,如:hover 或 :active。WebCore 会确保这些状态下的样式得到正确的反映。

一旦遍历完成并且所有可见的渲染对象都被绘制到了屏幕上,绘制阶段就结束了。

合成

为了提高性能,现代浏览器会尽可能地利用合成。例如,当你使用像transform或opacity这样的 CSS 属性时,浏览器可能会为该元素创建一个新的合成层。这样,当该元素发生变化时,浏览器只需要更新那个合成层,而不是整个页面。这大大提高了性能,特别是在移动设备和低功耗设备上。

合成(Compositing)主要是在 GPU 中进行的。现代浏览器为了提高渲染性能,尤其是动画和页面的平滑滚动,会尽量将合成任务交给 GPU 处理。这是因为 GPU 在处理像素和图层操作上特别高效,特别是涉及大量并行计算时。

当浏览器决定为某个元素创建一个新的合成层时(例如,使用了transform、opacity、filters或其他会触发合成的 CSS 属性时),该元素的渲染内容会被发送到 GPU,存在一个称为纹理(texture)的结构中。随后,当这个元素需要移动或进行其他视觉变化时,GPU 只需简单地操作这个纹理,而无需重新计算或重绘整个页面。这样可以大大提高性能。

简而言之,合成是在 GPU 中进行的,利用了 GPU 的并行处理能力和专门的图形处理技术来实现高效渲染。

合成主要是在 GPU 中将不同的图层组合到一起以形成最终的页面视图。在这个过程中,各个图层可以独立地进行移动、缩放或调整透明度等操作,而不需要重新绘制整个页面。利用 GPU 进行合成可以提高渲染速度和效率。

对比图形引擎

3D 图形引擎是专门用于创建、渲染和操作 3D 内容的软件框架。它通常包括物理模拟、光照计算、动画、模型加载等功能。

以 three.js 为例,它使用 WebGL API 在浏览器中进行 3D 渲染。而浏览器中的常规页面渲染,例如使 WebCore 的渲染,是基于浏览器的标准渲染流程,主要处理 2D 内容。

three.js 旨在创建 3D 世界和效果,而浏览器的 2D 渲染更关心内容的结构和样式。

核心概念对比

当我们试图类比浏览器的 2D 页面渲染和 three.js 的 3D 渲染时,可以发现一些相似的核心概念,尽管这些概念在每个上下文中可能有所不同。以下是一些相似性:

元素/物体

  • 2D 页面渲染:页面上的每个 HTML 元素,如<div>, <img>, <p>等。

  • three.js/3D 渲染:场景中的每个 3D 物体,如THREE.Mesh, THREE.Group等。

样式/材质

层次结构/场景

视图/摄像机

  • 2D 页面渲染:视口定义了用户当前可以看到的页面部分。

  • three.js/3D 渲染:摄像机定义了用户从哪个角度和位置看到 3D 场景。

光照/颜色

  • 2D 页面渲染:颜色定义了元素的背景、文本和边框颜色。

  • three.js/3D 渲染:光源影响了物体的颜色和明暗,与物体的材质和纹理结合,决定了其最终的外观。

动画/变换

  • 2D 页面渲染:CSS 动画和转换可以改变元素的位置、大小、颜色等。
  • three.js/3D 渲染:动画库和变换方法可以改变物体的位置、大小、旋转等。

交互/事件

  • 2D 页面渲染:可以使用事件监听器捕捉元素的点击、鼠标悬停、焦点等事件。
  • three.js/3D 渲染:通过光线投射,可以监听物体的点击、交叉、拖放等事件。

渲染过程对比

步骤 WebCore Three.js
CPU 资源加载 加载 HTML、CSS、JS 文件 加载 3D 模型、纹理、着色器等资源
CPU 处理 解析 HTML、CSS 和 JavaScript 代码生成 DOM 和 CSSOM 树 解析和执行 Three.js 脚本,构建 3D 场景
CPU 交互 JavaScript 监听和处理用户交互事件,如点击、滚动等 Three.js 监听鼠标、键盘和触摸事件,更新 3D 场景状态
CPU 布局 计算页面中每个元素的大小和位置生成布局树 定义场景、摄像机、灯光、物体等位置和属性
CPU 绘制预备 创建渲染树,结合 DOM 和 CSSOM 传递顶点数据、纹理、灯光信息等到 GPU
GPU **绘图 **API 平台特定 API WebGL/WebGL2
GPU 与硬件交互 通常通过平台的底层 API 与 GPU 交互 直接通过 WebGL 与 GPU 交互
GPU 顶点处理 不适用于传统的 2D 页面渲染 GPU 上的顶点着色器处理顶点数据、转换 3D 坐标到 2D 屏幕坐标
GPU 绘制/光栅化 为每个元素生成像素颜色 GPU 的片段着色器为每个像素计算颜色、光照、阴影等
GPU 合成 GPU 将多个图层和特效合并到一个完整的 2D 页面视图中 渲染结果被绘制到 HTML 的 Canvas 元素上,如果有 post-processing 也在这里完成
GPU 显示 GPU (更新屏幕缓冲) GPU (更新屏幕缓冲)
显示 渲染目标 操作系统窗口或选项卡 HTML Canvas 元素

进化中的变和不变

图形引擎的演变

从 2005 年 Unity 的亮相,到 2010 年 Three.js 的出现,再到 2013 年 Babylon.js 的发布,不断演进出新的图形引擎并在各自领域发挥作用。

  • 变的是底层技术和上层框架:在时间的长河中,上层的应用框架持续调整、优化,底层的渲染技术也衍生出从前向渲染、后向渲染、全局光、基于物理的渲染等技术,再到到 WebGL1、WebGL2、WebGPU 等底层的进化。

  • 不变的是概念模型:即使技术在进步,某些核心元素如网格、材质、纹理和灯光等概念始终保持不变。

浏览器的演进

浏览器的历史自 1995 年 IE 的诞生开始,经历了 2003 年 Safari 的发布,再到 2008 年 Chrome 的出现。

  • 变的是底层技术和上层框架: 在各种应用框架如 jQuery、Angular、React 的推出与退场中,底层的渲染技术也在不断的升级与优化。

  • 不变的是概念模型:尽管浏览器技术在飞速进化,但盒模型、结构树、样式树和渲染树这些核心概念始终保持其原始的形态。

所以,无论是图形引擎还是浏览器,面对各种创新与挑战,都需要有一个稳固的基础。这就像建筑,无论外部如何装修,基石始终不变。当我们面对不同的领域,构建系统的解决方案时,构建模型成是首先要思考的问题。在应用层面,需要不断为特定的细分领域找到最佳的解决方案;而在底层,持续优化效率是确保长远发展的关键。

相关推荐
长天一色8 分钟前
【ECMAScript 从入门到进阶教程】第三部分:高级主题(高级函数与范式,元编程,正则表达式,性能优化)
服务器·开发语言·前端·javascript·性能优化·ecmascript
NiNg_1_23426 分钟前
npm、yarn、pnpm之间的区别
前端·npm·node.js
秋殇与星河28 分钟前
CSS总结
前端·css
BigYe程普1 小时前
我开发了一个出海全栈SaaS工具,还写了一套全栈开发教程
开发语言·前端·chrome·chatgpt·reactjs·个人开发
余生H1 小时前
前端的全栈混合之路Meteor篇:关于前后端分离及与各框架的对比
前端·javascript·node.js·全栈
程序员-珍1 小时前
使用openapi生成前端请求文件报错 ‘Token “Integer“ does not exist.‘
java·前端·spring boot·后端·restful·个人开发
axihaihai1 小时前
网站开发的发展(后端路由/前后端分离/前端路由)
前端
流烟默1 小时前
Vue中watch监听属性的一些应用总结
前端·javascript·vue.js·watch
2401_857297912 小时前
招联金融2025校招内推
java·前端·算法·金融·求职招聘
茶卡盐佑星_2 小时前
meta标签作用/SEO优化
前端·javascript·html