Chromium硬件加速渲染的UI合成过程资料Word格式文档下载.docx
- 文档编号:6287668
- 上传时间:2023-05-06
- 格式:DOCX
- 页数:110
- 大小:202.84KB
Chromium硬件加速渲染的UI合成过程资料Word格式文档下载.docx
《Chromium硬件加速渲染的UI合成过程资料Word格式文档下载.docx》由会员分享,可在线阅读,更多相关《Chromium硬件加速渲染的UI合成过程资料Word格式文档下载.docx(110页珍藏版)》请在冰点文库上搜索。
ActiveLayerTree代表的是一个可以被Browser端合成的UI。
LayerTree和PendingLayerTree的存在使得Render线程和Compositor线程可以并发绘制网页的UI,如图2所示:
这相当于是网页UI的某一帧绘制分为两部分。
前半部分由Render线程处理,后半部分由Compositor线程处理。
其中,第N+1帧的前半部分和第N帧的后半部分可以并发处理。
这一点类似于Android5.0应用程序UI硬件加速渲染机制,具体可以参考这个系列的文章。
其中,这里的Render线程和Compositor线程就相当于Android5.0应用程序进程中的Main线程和Render线程。
从前面一文可以知道,Render端执行GPU命令绘制网页UI时,只不过是将要执行的GPU写入到一个GPU命令缓冲区中,然后由GPU进程从这个GPU命令缓冲区读出GPU命令,并且调用相应的OpenGL函数执行它们。
这个过程实际上是增加了网页渲染过程中的并行度,也就是Render端在GPU命令缓冲区写入GPU命令的同时,GPU进程从GPU命令缓冲区读出GPU命令进行处理。
这样可以很好地利用设备的多核特性。
这一点也是Chromium的硬件加速渲染与Android的硬件加速渲染的重要区别之一。
PendingLayerTree和ActiveLayerTree的存在使用Browser端在任何时刻都有网页UI可以合成。
ActiveLayerTree描述网页内容发生变化前的一帧UI。
对PendingLayerTree进行光栅化是一个漫长的过程。
如果没有ActiveLayerTree的存在,那么就会导致在PendingLayerTree光栅化期间,Browser端没有网页UI可以显示在屏幕上。
早期,Render端先通过一个称为GLRenderer的渲染器将ActiveLayerTree绘制在一个纹理中,然后再将绘制好的纹理传递给Browser端合成,如图3所示:
ActiveLayerTree中的每一个Layer都对应有一个RenderPass,这些RenderPass组成一个RenderPassList。
其中,每一个RenderPass又包含有一个QuadList。
QuadList由一系列的DrawQuad组成。
一个DrawQuad描述的是一个纹理绘制命令,这个纹理绘制命令指定了纹理对象和纹理坐标等信息。
前面提到,WebGL端负责绘制网页中的canvas标签。
这个canvas标签的内容被绘制在一个纹理中。
这个纹理是在WebGL端OpenGL上下文中生成的,然后通过Mailbox传递给Render端。
前面提到,网页中的canvas标签被抽象为一个TextureLayer对象。
这个TextureLayer对象在RenderPassList中对应有一个RenderPass。
这个RenderPass的QuadList包含有一个TextureDrawQuad。
这个TextureDrawQuad指定的纹理对象描述的就是canvas标签的UI。
换句话说,就是WebGL端将canvas标签的UI绘制在一个纹理上。
注意,这个纹理对象是在WebGL端OpenGL上下文中生成的,Render端OpenGL上下文不能直接访问它。
为了使得Render端可以访问这个纹理对象,WebGL端通过Mailbox将这个纹理对象传递给Render端,这样Render端就可以访问它了。
Render端最后通过GLRenderer将RenderPassList的所有RenderPass,包括canvas标签对应的RenderPass,都绘制在一个纹理中。
这个纹理接下来又会通过Mailbox传递给Browser端。
Browser端像Render端一样,也是将自己要绘制的UI(包括了从Render端传递过来的纹理对象)抽象成LayerTree、PendingLayerTree和ActiveLayerTree三棵Tree。
Browser端的ActiveLayerTree也是对应有一个RenderPassList。
这个RenderPassList最终也是通过一个GLRenderer进行绘制。
不过,这个RenderPassList将会被绘制在屏幕中,而不是被绘制在一个纹理中。
从前面的分析就可以知道,通过GLRenderer,Render端首先将自己的RenderPassList绘制在一个纹理中。
这个纹理传递给Broswer端后,再次被绘制在屏幕中。
这意味着Render端的UI被绘制了两次。
第一次在Render端OpenGL上下文中绘制,第二次是在Browser端OpenGL上下文中绘制。
实际上,我们可以直接将Render端的RenderPassList传递给Browser端绘制。
这样就可以减少一次绘制,从而提高效率。
将Render端的RenderPassList传递给Browser端是通过一个称为DelegatedRenderer的渲染器实现的,如图4所示:
Render端的RenderPassList经过DelegatedRenderer处理后,形成一个CompositorFrame。
这个CompositorFrame传递给Browser端之后,就会形成Browser端的ActiveLayerTree中的一个Layer,从而被绘制在屏幕中。
Render端的RenderPassList包含的纹理对象,包括WebGL端生成的纹理对象,都是通过Mailbox传递给Browser端访问的。
在上面的描述过程中,我们提到了LayerTree、PendingLayerTree、ActiveLayerTree、RenderThread、CompositorThread、RenderPass、DrawQuad、GLRenderer、DelegatedRenderer和CompositorFrame等概念,它们都是属于Chromium中的Compositor模块的概念。
Chromium中的Compositor模块简称为CC模块,它负责合成Render端和Browser的UI,在接下来的分析过程中,我们只是简单涉及到它的内容。
在以后分析网页渲染的文章中,我们会再详细分析CC模块的实现原理。
在上面的描述过程中,我们一再提到了Chromium的Mailbox机制,它在Browser端合成Render端和WebGL端UI的过程中起到传递资源的作用,使得一个OpenGL上下文可以访问在另外一个OpenGL上下文中创建的资源。
因此,接下来我们就首先分析Chromium的Mailbox机制。
Mailbox的定义很简单,就是一个名称,如下所示:
[cpp]viewplaincopy
structGPU_EXPORTMailbox{
Mailbox();
boolIsZero()const;
voidSetZero();
voidSetName(constint8_t*name);
//Generateauniqueunguessablemailboxname.
staticMailboxGenerate();
......
int8_tname[GL_MAILBOX_SIZE_CHROMIUM];
};
这个结构体定义在文件external/chromium_org/gpu/command_buffer/common/mailbox.h中。
从这里可以看到,Mailbox的名称使用一个int8_t数组name描述。
一个有效的Mailbox的名称是非0的,也就是数组name不是全0的。
在创建一个Mailbox的时候,它的名称默认被设置为0,如下所示:
Mailbox:
:
Mailbox(){
memset(name,0,sizeof(name));
}
这个函数定义在文件external/chromium_org/gpu/command_buffer/common/mailbox.cc中。
以后我们可以通过Mailbox结构体的成员函数SetName设置一个Mailbox的名称,如下所示:
voidMailbox:
SetName(constint8*n){
DCHECK(IsZero()||!
memcmp(name,n,sizeof(name)));
memcpy(name,n,sizeof(name));
还可以通过Mailbox结构体的成员函数SetZero将一个Mailbox的名称设置为0,如下所示:
SetZero(){
Mailbox结构体还提供了成员函数IsZero判断一个Mailbox的名称是否为0,如下所示:
boolMailbox:
IsZero()const{
for(size_ti=0;
i<
arraysize(name);
++i){
if(name[i])
returnfalse;
}
returntrue;
我们可以通过Mailbox类静态成员函数Generate生成一个名称不为0的Mailbox,如下所示:
MailboxMailbox:
Generate(){
Mailboxresult;
//Generatescryptographically-securebytes.
base:
RandBytes(result.name,sizeof(result.name));
returnresult;
一般来说,我们不直接调用Mailbox类静态成员函数Generate生成一个Mailbox,而是通过OpenGL接口类GLES2Implementation的成员函数GenMailboxCHROMIUM生成,如下所示:
voidGLES2Implementation:
GenMailboxCHROMIUM(
GLbyte*mailbox){
gpu:
Mailboxresult=gpu:
Generate();
memcpy(mailbox,result.name,sizeof(result.name));
这个函数定义在文件external/chromium_org/gpu/command_buffer/client/gles2_implementation.cc中。
生成的Mailbox通过输出参数mailbox返回给调用者。
调用者获得生成的Mailbox之后,继续调用GLES2Implementation的成员函数ProduceTextureCHROMIUM将该Mailbox与一个纹理对象进行关联,如下所示:
ProduceTextureCHROMIUM(GLenumtarget,
constGLbyte*data){
helper_->
ProduceTextureCHROMIUMImmediate(target,data);
CheckGLError();
参数data描述的是一个Mailbox,另外一个参数target描述的是要关联的纹理对象。
从前面一文可以知道,GLES2Implementation类的成员变量helper_指向的是一个GLES2CmdHelper对象,这里调用它的成员函数ProduceTextureCHROMIUMImmediate向GPU命令缓冲区写入一个gles2:
cmds:
ProduceTextureCHROMIUMImmediate命令,以便传递给GPU进程处理。
GPU进程将gles2:
ProduceTextureCHROMIUMImmediate命令分发给GLES2DecoderImpl类的成员函数DoProduceTextureCHROMIUM处理,处理过程如下所示:
voidGLES2DecoderImpl:
DoProduceTextureCHROMIUM(GLenumtarget,
TextureRef*texture_ref=texture_manager()->
GetTextureInfoForTarget(
&
state_,target);
ProduceTextureRef("
glProduceTextureCHROMIUM"
texture_ref,target,data);
这个函数定义在文件external/chromium_org/gpu/command_buffer/service/gles2_cmd_decoder.cc中。
GLES2DecoderImpl类的成员函数DoProduceTextureCHROMIUM首先调用成员函数texture_manager获得一个TextureManager对象。
这个TextureManager对象负责管理当前正在使用的OpenGL上下文所在的共享组的纹理对象。
有了这个TextureManager对象之后,就可以调用它的成员函数GetTextureInfoForTarget获得参数target描述的纹理引用对象。
有了这个纹理引用对象之后,GLES2DecoderImpl类的成员函数DoProduceTextureCHROMIUM接下来调用另外一个成员函数ProduceTextureRef执行下一步操作。
GLES2DecoderImpl类的成员函数ProduceTextureRef的实现如下所示:
ProduceTextureRef(std:
stringfunc_name,
TextureRef*texture_ref,GLenumtarget,constGLbyte*data){
constMailbox&
mailbox=*reinterpret_cast<
constMailbox*>
(data);
.......
Texture*produced=texture_manager()->
Produce(texture_ref);
group_->
mailbox_manager()->
ProduceTexture(target,mailbox,produced);
GLES2DecoderImpl类的成员函数ProduceTextureRef首先将参数data强制转换成一个Mailbox结构体,接着又调用前面描述的TextureManager对象的成员函数Produce获得参数texture_ref描述的纹理引用对象所引用的纹理对象,如下所示:
Texture*TextureManager:
Produce(TextureRef*ref){
DCHECK(ref);
returnref->
texture();
这个函数定义在文件external/chromium_org/gpu/command_buffer/service/texture_manager.cc中。
TextureManager类的成员函数Produce调用参数ref描述的TextureRef对象的成员函数texture即可获得它所引用的纹理对象。
这个纹理对象使用一个Texture对象描述。
回到GLES2DecoderImpl类的成员函数ProduceTextureRef中,它接下来调用成员变量group_指向的一个ContextGroup对象的成员函数mailbox_manager获得一个MailboxManager对象。
有了这个MailboxManager对象之后,就调用它的成员函数ProduceTexture执行下一步操作。
GLES2DecoderImpl类的成员变量group_指向的ContextGroup对象描述的是一个资源共享组,调用这个ContextGroup对象的成员函数mailbox_manager获得的MailboxManager对象用来管理当前正在使用的OpenGL上下文所属的OpenGL上下文共享组的那些被Mailbox引用的纹理对象。
这意味着在同一个OpenGL上下文共享组的不同OpenGL上下文,可以直接访问与OpenGL上下文共享组关联的MailboxManager对象所管理的纹理对象,这是因为在同一个OpenGL上下文共享组的不同OpenGL上下文本来就是可以相互访问各自创建的纹理对象的。
这一点我们后面可以看到。
上面我们提到了资源共享组和OpenGL上下文共享组,它们的区别可以参考前面一文。
现在我们继续分析MailboxManager类的成员函数ProduceTexture的实现,如下所示:
voidMailboxManager:
ProduceTexture(unsignedtarget,
mailbox,
Texture*texture){
TargetNametarget_name(target,mailbox);
InsertTexture(target_name,texture);
这个函数定义在文件external/chromium_org/gpu/command_buffer/service/mailbox_manager.cc中。
参数texture指向的Texture对象实际上就是参数target描述的纹理对象。
MailboxManager类的成员函数ProduceTexture所要做的事情就是将这个纹理对象与参数mailbox描述的Mailbox关联起来,也就是以参数target和参数mailbox组成的一个TargetName对象为键值,把参数texture描述的纹理对象保存在MailboxManager类的成员变量mailbox_to_textures_描述的一个std:
map中。
这是通过调用MailboxManager类的成员函数InsertTexture实现的,如下所示:
InsertTexture(TargetNametarget_name,Texture*texture){
texture->
SetMailboxManager(this);
TextureToMailboxMap:
iteratortexture_it=
textures_to_mailboxes_.insert(std:
make_pair(texture,target_name));
mailbox_to_textures_.insert(std:
make_pair(target_name,texture_it));
DC
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- Chromium 硬件加速 渲染 UI 合成 过程 资料