高性能Web动画和渲染原理系列(4)“Compositor-Pipeline演讲PPT”学习摘要
目录
示例代码托管在:http://www.github.com/dashnowords/blogs
博客园地址:《大史住在大前端》原创博文目录
华为云社区地址:【你要的前端打怪升级指南】
附件PPT来自chromium官方网站开发文档。术语里的
cc
指的是Chromium Compositor
一直以来都想了解浏览器合成层的运作机制,但是相关的中文资料大多比较关注框架和开发技术,这方面的资料实在是太少了,后来在chromium
官方网站的文档里找到了项目组成员malaykeshav在 2019年4月的一份关于浏览器合成流水线的演讲PPT,个人感觉里面讲的非常清楚了,由于没有找到视频,有些部分只能自行理解,本文仅对关键信息做一些笔记,对此感兴趣的读者可以在文章开头的github
仓库或附件中拿到这个PPT自行学习。
摘要
1.合成流水线
合成流水线,就是指浏览器处理合成层的工作流程,其基本步骤如下:
大致的流程就是说Paint
环节会生成一个列表,列表里登记了页面元素的绘制指令,接着这个列表需要经过Raster
光栅化处理,并在合成帧
中处理纹理,最后的Draw
环节才是将这些纹理图展示在浏览器内容区。
2. 预定义UI层
chromium中预定义了一些指定类型的UI层,大致分为:
- Not Drawn - 为了处理透明度或滤镜效果、transform变形或者clip剪裁的非绘制层
- Solid color layer - 固有颜色层
- Painted texture layer - Texture纹理会在这个层执行
paint
渲染和后续的rasterized
光栅化任务 - Transferable resource layer - 共享资源层,可能是GPU里面的Texture纹理也可能未来会发给GPU的位图
- Surface layer - 临时占位层,因为自顶向下遍历layer树时子树都还没处理,需要先占位最后再填充
- Nine patch layer - 用于实现阴影的层
3. paint是什么意思
每个层layer
是由若干个views
组成的,所谓paint
,就是每个views
将自己对应图形的绘制指令添加到层的可展示元素列表Display Item List
里,这个列表会被添加到一个延迟执行的光栅化任务中,并最终生成当前层的texture纹理(可以理解为当前层的绘制结果),考虑到传输性能以及未来增量更新的需求,光栅化的结果会以tiles
瓦片形式保存。在chrome中也可以看到页面瓦片化拆分的结果:
4. 分层的优势和劣势
分层的优势和劣势也在此进行了说明,和之前我们主动思考的答案基本一致(暗爽一下)。
5. 视图属性及其处理方式
views
中支持的属性包含Clip
剪裁,transform
变换,effect
效果(如半透明或滤镜等),mask
遮罩,通常按照后序遍历的方式自底向上进行遍历处理。
clip
剪裁的处理方式是在父节点和子节点之间插入一个剪裁层,用来将其子树的渲染结果剪裁到限定的范围内,然后再向上与父级进行合并;
transform
变换直接作用于父节点,处理到这个节点时其子树都已经处理完毕,直接将整体应用变形即可;
effect
效果一般直接作用于当前处理的节点,有时也会产生交叉依赖的场景;
PPT第40页中在介绍effect
效果处理时描述了两种不同的透明度处理需求,从而引出了一个Render Surface
的概念,它相当于一个临时的层,它的子树需要先绘制在这个层上,然后再向上与父节点进行合并,屏幕就是是根级的Render Surface
。
6. Quads
Layer
遍历处理输出的结果被称为Quads
(从意思上理解好像就是指输出了很多个矩形方块),每个quad
都持有它被绘制到目标缓冲区所需要的资源,根据它持有的资源不同可以分为:
Solid Color
-固定颜色型Texture
- 纹理型Tile
- 瓦片型Surface
- 临时绘图表面型Video
- 视频帧型Render Pass
-Render Surface
类型的占位区,Render Surface
子树处理完后填充到关联的Render Pass
7. Compositor Frame
合成层真正的工作要开始了,主角概念Compositor Frame
(合成帧)登场,它负责将quads
合并绘制在一起,胶片里59-62页非常清楚地展示了合成的过程,最终输出的结果就是根节点的纹理。
chromium
是多进程架构,Browser Process
浏览器进程会对菜单栏等等容器部分的画面生成合成帧来输出,每个网页的Render Process
渲染进程会对页面内容生成合成帧来输出,最终的结果都被共享给GPU Process
GPU进程进行聚合并生成最终完整的合成表面,接着在Display Compositor
环节将最后的位图展示在屏幕上。
8. 关于光栅化以及渲染方式
胶片里并没有描述具体的光栅化的处理过程,但是layer
输出的quads
看起来应该是光栅化以后的结果,推测应该是处理Display Item List
中的绘图指令时也和WebGL类似,经过顶点着色器
和片元着色器
的遍历式处理机制,并在过程中自动完成像素插值。
9.【重要】软件渲染和硬件渲染的区别
声明:本节内容是个人理解,仅用作技术交流,不保证对!
软件渲染和硬件渲染的区别对笔者而言一直非常抽象,只是知道基本概念。后来在【chromium开发者文档】(国内可能无法访问)中《Compositor Thread Architecture》这篇合成器线程架构的文章中找到了一些相关描述,也解开了笔者心中一直以来的疑惑,相关部分摘抄如下:
Texture Upload
One challenge with all these textures is that we rasterize them on the main thread of the renderer process, but need to actually get them into the GPU memory. This requires handing information about these textures (and their contents) to the impl thread, then to the GPU process, and once there, into the GL/D3D driver. Done naively, this causes us to copy a single texture over and over again, something we definitely don't want to do.
We have two tricks that we use right now to make this a bit faster. To understand them, an aside on “painting” versus “rasterization.”
- Painting is the word we use for telling webkit to dump a part of its RenderObject tree to a GraphicsContext. We can pass the painting routine a GraphicsContext implementation that executes the commands as it receives them, or we can pass it a recording context that simply writes down the commands as it receives them.
- Rasterization is the word we use for actually executing graphics context commands. We typically execute the rasterization commands with the CPU (software rendering) but could also execute them directly with the GPU using Ganesh.
- Upload: this is us actually taking the contents of a rasterized bitmap in main memory and sending it to the GPU as a texture.With these definitions in mind, we deal with texture upload with the following tricks:
- Per-tile painting: we pass WebKit paint a recording context that simply records the GraphicsContext operations into an SkPicture data structure. We can then rasterize several texture tiles from that one picture.
- SHM upload: instead of rasterizing into a void* from the renderer heap, we allocate a shared memory buffer and upload into that instead. The GPU process then issues its glTex* operations using that shared memory, avoiding one texture copy.The holy grail of texture upload is “zero copy” upload. With such a scheme, we manage to get a raw pointer inside the renderer process’ sandbox to GPU memory, which we software-rasterize directly into. We can’t yet do this anywhere, but it is something we fantasize about.
大概翻译一下,方便英语水平一般的小伙伴理解,GPU处理图片的方式是按照Texture进行贴图的,对此不熟悉的小伙伴可以查看笔者以前发的有关Three.js
相关的博文。
纹理上传:
处理纹理的挑战之一就是它是在渲染进程(可以理解为单个Tab网页的进程)的主线程里进行的,但是最终需要将其放入GPU内存。这就需要将纹理数据递交给合成器线程,然后再交给GPU进程(Chromium架构里有专门的GPU进程用来专门处理和GPU之间的协作任务),最后再传递给底层的Direct3D
或OpenGL
(也就是图形学的底层技术),如果只是按照常规流程来处理,就会需要一次又一次来复制生成的纹理数据,这显然不是我们想要的。
我们现在使用了两个小方法来使这个流程变得快一点。它们分别作用于painting
(绘制)和rasterization
(光栅化)两个阶段。
- 1号知识点!!!
Painting
我们用来告诉webkit为RenderObject Tree
的来生成对应的GraphicsContext
。通过给painting routine
(绘制流程)传递一个GraphicsContext
的具体实现来执行这些已经编排好的绘制命令,也可以传递一个record context
(记录上下文)只是简单地把绘图命令都记录下来。- 2号知识点!!!
Rasterization
(光栅化)是指Graphics context
关联的绘图命令实际被执行的过程。通常我们使用CPU(也就是软件渲染的方式)来执行光栅化任务,也可以直接使用GPU来渲染(也就是硬件渲染的方式)。- 上传:指在主线程存储区获取到光栅化以后的位图内容然后将它作为纹理上传给GPU的过程,考虑到上述已经提及的定义,上传过程是如下来处理的:
- 瓦片绘制:我们在webkit中使用
recording context
来简单地记录Graphics Context
的操作指令,将它存储为SkPicture类型(直接使用软件光栅化时生成的是SkBitmap类型),随后可以从一张picture里面光栅化处理得到多个纹理瓦片
。- 共享内存:在软件渲染的方式中,光栅化的结果会被存储在
renderer
进程的堆内存里,现在不这样搞了,我们重新分配了一块共享缓冲区,然后通过它来传递相关对象,GPU进程随后在获取纹理时直接从共享内存中获取就行了,这样就避免了数据的拷贝。
总的来说,纹理上传的过程几乎是零拷贝的。利用这样的结构,我们在renderer
进程(也就是网页的渲染进程)的沙箱环境内也可以获取到指向GPU 内存的指针,而在软件光栅化的过程中,是直接将位图结果放在这里的。
- Painting: this is the process of asking Layers for their content. This is where we ask webkit to tell us what is on a layer. We might then rasterize that content into a bitmap using software, or we might do something fancier. Painting is a main thread operation.
- Drawing: this is the process of taking the layer tree and smashing it together with OpenGL onto the screen. Drawing is an impl-thread operation.
- painting:表示的过程是向Layers对象查询层内容,也就是让webkit告诉我们每一层上面到底有什么。接下来我们就可以使用软件光栅化的方式将这些内容处理为位图,也可以做一些更牛的事情,painting是一个主线程行为。
- drawing:是指将Layer中的内容用OpenGL绘制在屏幕上的过程,它是另一个线程中的操作。
概念比较多没有基础的读者可能理解起来有难度,我尝试用自己的话复述一下:
【软件渲染】的模式下,在paint
时会直接利用Graphics Context
绘图上下文将结果绘制出来,在一个SkBitmap
实例中保存为位图信息;【硬件渲染】的模式下,在paint
时传入一个SkPicture
实例,将需要执行的绘图命令保存在里面先不执行,然后通过共享内存将它传给GPU进程,借助GPU来最终去执行绘图命令,生成多个瓦片化的位图纹理结果(OpenGL
中顶点着色器向片元着色器传递数据时可以自动进行数据插值,完成光栅化的任务)。 纯软件渲染里严格说是没有合成层概念的,因为最终输出的只有一张位图,按照顺序从下往上画,和画到一个新层上再把新层贴到已有结果上其实是一样的。
不管使用哪种途径,paint
动作都是得到位图数据,而最终的draw
这个动作是借助OpenGL和位图数据最终把图形显示在显示器上。
所以【硬件渲染】就是渲染进程把要做的事情和需要的数据都写好,然后打包递给GPU让它去干活。
高性能Web动画和渲染原理系列(4)“Compositor-Pipeline演讲PPT”学习摘要的更多相关文章
- 高性能Web动画和渲染原理系列(3)——transform和opacity为什么高性能
示例代码托管在:http://www.github.com/dashnowords/blogs 博客园地址:<大史住在大前端>原创博文目录 华为云社区地址:[你要的前端打怪升级指南] [T ...
- 高性能Web动画和渲染原理系列(1)——CSS动画和JS动画
[摘要] 介绍CSS动画和JS动画的基本特点,以及轻量级动画库velocity.js的基本用法. 示例代码托管在:http://www.github.com/dashnowords/blogs 博客园 ...
- 高性能Web动画和渲染原理系列(5)合成层的生成条件和陷阱
目录 一. 硬件加速相关的几个概念 二. 合成层的生成条件 显式提升 隐式提升 三. 硬件加速的权衡 四. 动画实现的一些建议 示例代码托管在:http://www.github.com/dashno ...
- 高性能Web动画和渲染原理系列(2)——渲染管线和CPU渲染
目录 一. 高性能动画 二. 像素渲染管线 基本渲染流程 回流和重绘 三. 旧软件渲染 渲染对象(RenderObject) 渲染层(RenderLayer) 四. 从canvas体会分层优势 不分层 ...
- Web高性能动画及渲染原理(1)CSS动画和JS动画
目录 一. CSS动画 和 JS动画 1.1 CSS动画 1.2 JS动画 1.3 小结 二. 使用Velocity.js实现动画 示例代码托管在:http://www.github.com/dash ...
- 【Web动画】CSS3 3D 行星运转 && 浏览器渲染原理
承接上一篇:[CSS3进阶]酷炫的3D旋转透视 . 最近入坑 Web 动画,所以把自己的学习过程记录一下分享给大家. CSS3 3D 行星运转 demo 页面请戳:Demo.(建议使用Chrome打开 ...
- nginx高性能WEB服务器系列之六--nginx负载均衡配置+健康检查
nginx系列友情链接:nginx高性能WEB服务器系列之一简介及安装https://www.cnblogs.com/maxtgood/p/9597596.htmlnginx高性能WEB服务器系列之二 ...
- 《Nginx高性能Web服务器》系列分享专栏
<Nginx高性能Web服务器>系列分享专栏 [作者:Poechant] Nginx是目前最流行的基于BSD-like协议.轻量级.高性能的HTTP服务器.反向代理服务器和电子邮件(SMT ...
- nginx高性能WEB服务器系列之九--nginx运维故障日常解决方案
nginx系列友情链接:nginx高性能WEB服务器系列之一简介及安装https://www.cnblogs.com/maxtgood/p/9597596.htmlnginx高性能WEB服务器系列之二 ...
随机推荐
- PowerBI系列之什么是PowerBI
大家好,我是小黎子!一个专注于数据分析整体数据仓库解决方案的程序猿!今天小黎子就给大家介绍一个数据分析工具由Microsoft出品的全新数据可视化工具Power BI.微软Excel很早就支持了数据透 ...
- 破阵九解:Node和浏览器之事件循环/任务队列/异步顺序/数据结构
前言 本文内容比较长,请见谅.如有评议,还请评论区指点,谢谢大家! >> 目录 开门见山:Node和浏览器的异步执行顺序问题 两种环境下的宏任务和微任务(macrotask &&a ...
- python requests自动化框架
一.项目结构 1.新建一个工程(一定要创建工程),工程名称自己定义,如:yoyo_jiekou 2.在工程的跟目录新建一个脚本:run_main.py,用来执行全部用例 3.在工程下创建以下几个pak ...
- Jenkins部署(基于windows)
一.安装jdk,配置环境变量 二.安装tomcat和jenkins 1.检查电脑上8080端口是否被占用: 命令行中输入:netstat -ano 2.下载Tomcat Tomcat官方网站:http ...
- maven子项目导出成jar包及运行
第一步:选这idea右侧栏的maven projects 第二步:选中需要打包成jar包的项目下的lifecycle 第三步:选中package 第四步:点击开始导出 第五步:使用winRAR打开ja ...
- SpringBoot2.x--入门篇--01--HelloWorld
很多人说,学习springboot至少需要spring基础,servlet基础等等,笔者不敢苟同.凡是有一定java基础的人,都可以直接学习springboot,当学到原理和源码时,通过查缺补漏的方式 ...
- Python开发【第十篇】集合
集合的运算 & 交集 | 并集 - 补集 ^ 对称补集 < 子集 > 超集 例子: 生成两个集合的并集 s1 = {1,2,3} s2 = {2,3,4} s3 = s1|s2 # ...
- Vuex使用总结
Vuex 是什么? Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式.它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化. Vuex的五个核心概念 ...
- vue-property-decorator用法
vue-property-decorator这个库完全依赖于vue-class-component,所以在使用这个库之前请先阅读它, 不管啥反正都是装饰器而已 vue-property-decorat ...
- 手写一个简单的ElasticSearch SQL转换器(一)
一.前言 之前有个需求,是使ElasticSearch支持使用SQL进行简单查询,较新版本的ES已经支持该特性(不过貌似还是实验性质的?) ,而且git上也有elasticsearch-sql 插件, ...