热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Chromium的GPU硬件加速

转:http:blog.csdn.netmilado_njuarticledetails7216145#Chromium的GPU硬件加速##概述这里所说的GPU硬件加速是指应用GP

转:http://blog.csdn.net/milado_nju/article/details/7216145

# Chromium的GPU硬件加速

## 概述

这里所说的GPU硬件加速是指应用GPU的图形性能对chromium中的一些图形操作交给GPU来完成,因为GPU是专门为处理图形而设计,所以它在速度和能耗上更有效率。但是,使用GPU加速有些额外开销,并且某些图形操作CPU完成的会更快,因而不是所有的操作都合适交给GPU来做。

Chromium中,GPU加速可以不仅应用于3D,而且也可以应用于2D。这里,GPU加速通常包括以下几个部分:Canvas2D,布局合成(Layout Compositing), CSS3转换(transitions),CSS3 3D变换(transforms),WebGL和视频(video)。目前chromium对这些的支持已经越来越充分,只是某些方面可能还存在些正确性和性能问题。

Chromium除了对以上采用GPU硬件加速之外,在新的views框架中,引入了对浏览器主界面采用硬件加速的机制。 它可以把浏览器主界面上的各种工具栏等和网页通过GPU合成(compositing)起来。因为之前网页布局也用到合成器,目前两个合成器各自为战,所以chromium会实现一个新的合成器叫chrome compositor,关于它的细节,我会在专门的章节来做介绍。

本章主要介绍GPU进程相关的内容,但是不涉及各个部分的加速实现。具体的各个加速实现及WebKit对GPU硬件加速的支持,后面会有分别的章节来介绍。

 ## 启用GPU加速

如果想使用Chromium的GPU硬件加速功能,首先需要你的GPU驱动程序不在chromium的黑名单中。因为很多的GPU驱动程序存在很多的错误,这些错误可能会比较严重的影响了chromium的稳定,例如导致程序崩溃,所以这些GPU被列在黑名单中。一个检测的简单办法是在地址栏里输入“about:gpu”查看相关GPU的信息,检查相关加速是否已经打开。

如果你的GPU驱动不幸在黑名单中,首先的办法是升级你的驱动,然后重新启动chromium。如果还是解决不了问题,可以通过在chromium的启动参数中加入“–ingore-gpu-blacklist”来关闭黑名单功能,这样你就开启了你的GPU加速功能。但是,如前所说,这种方法可能会造成chromium的不稳定,因而只是权宜之计。

 

## 进程模型

由于chromium的安全模型和稳定性考虑,GPU加速也采用多进程模型来实现。所以的GPU加速相关的操作均有一个独立的进程来完成,这就是GPU进程。详见下图所示GPU进程和Browser,Renderer进程。

《Chromium的GPU硬件加速》

GPU进程由Browser进程来创建和销毁,这类似于对plugin进程的管理。它们之间的通信是通过chromium的IPC消息机制实现的。Chromium只会创建一个GPU进程,该进程被所有的Renderer进程和Pepper plugin进程所共享,但是GPU进程会为不同的进程创建不同的command buffer的示例。对于一个Renderer进程,GPU进程也可以为其创建多个示例,这取决于Renderer进程的需求。

下面主要介绍以下GPU进程和客户进程(以Renderer进程示例)之间是如何工作的。下图描述了以WebGL为示例的主要模块(类)及它们之间的联系。

《Chromium的GPU硬件加速》

首先来看一看Renderer进程的模块类:

         WebGraphicsContext3DCommandBufferImpl:继承自WebKit::WebGraphicsContext3D类, 具体的实现类,主要是转接自WebKit的调用到chromium的具体实现。主要包括一个RenderGLContext对象。

         RendererGLContext:  Renderer进程对GLContext的一个封装,包括所有用于跟GPU进程交互的类,有一个GLES2Implementation对象,一个CommandBufferProxy对象和一个GPUChannelHost对象。

         GLES2Implementation:该类模拟GLES2,但是不直接调用GLES2的实现,而是将这些调用转换成特定格式的命令存入CommandBuffer中。

         CommandBufferHelper: 该类是一个辅助类,包括一个CommandBuffer代理类和一个共享内存

         CommandBufferProxy:CommandBuffer的一个代理类,实现CommandBuffer的接口,用于和CommandBufferStub之间的通信

         GPUChannelHost:用于IPC消息的通信类

接着再挨个了解一下GPU进程中的模块类:

         GPUChannel:用于GPU进程中的IPC消息的通信类

         GPUCommandBufferStub:CommandBuffer的桩,接受来自于CommandBufferProxy的消息,将请求交给CommandBufferService处理

         CommandBufferService:具体的CommandBuffer的实现类,但是其实它并不具体解析和执行这些命令,而是当有新的命令时,触发给注册的回调函数来处理

         GPUScheduler:负责调度执行commandbuffer的命令,它会检查该commandbuffer是否应该被执行,并适时将命令交给CommandParser的来处理

         CommandParser:仅检查CommandBuffer中的命令的头部,其余交给具体的decoder来做

         GLES2DecoderImpl:解析每条具体的命令并执行调用GL相应的函数

         GLImplementation Wrapper: 一组GL相关的函数指针,通过用户的设定来读取相应gl库的函数地址来设置自己

         GLLibraries: 具体的函数库,可以是opengl,opengles,mesagl,mock等

通过上面每个模块类的具体介绍,相信你已经大概知道它们的工作过程。那么,它们是如何同步的呢?因为Renderer进程需要等待GPU进程做好某些操作之后才继续执行。答案是,GPU进程处理一些命令后,会向Renderer进程报告当前自己当前的状态,Renderer进程通过检查状态信息和自己的期望结果来确定是否满足自己的条件。

GPU进程最终绘制的结果不再像软件渲染那样通过共享内存传递给Browser进程,而是直接将页面的内容绘制在浏览器的标签窗口内。

## Command Buffer

Command Buffer主要用于GPU进程(且称为GPU 服务端)和GPU的调用者进程(且称GPU客户端, 如Renderer进程, Pepperplugin进程)传递GPU操作命令。从接口上来,它只提供一些基本的接口来对buffer进行管理,它没有对buffer的具体方式和命令的格式进行任何限制。

现有实现是基于共享内存的方式来完成,因而命令是基于gles编码成特定的格式存储在共享内存中。共享内存方式采用了ring buffer的方式来管理,这表示内存可以循环使用,旧的命令会被新的命令所覆盖。基于gles的编码格式,因为WebGL是基于gles的Javascript绑定,所以简单直观。

### 命令基本格式

一条命令可以分成两个部分:命令头和命令体。命令头包含两个部分,一个是命令的长度,一个是命令的ID。命令体包含该命令所需要的其他信息,例如命令的立即操作数。命令是可以固定长度的,也可以是变长的,一起取决于该命令。具体的结构如下图所示。

《Chromium的GPU硬件加速》

 

### 基于GLES2的命令

上面说到,本身Command Buffer是没有定义具体的命令,所以GLES2可以根据需要自己来定义。命令大概可以分成两类,第一类是公共的命令,主要用来操作桶(bucket),跳转,调用和返回。第二类是跟GLES2的函数相关的命令,主要用来操作GLES2的函数。

### IPC机制

前面提到,命令本身是保存在共享内存中的,而且每条命令的长度不能超过(1<<21 -1),而且共享内存的大小也是固定的,如果命令太长,可存储的命令很少。那么问题就出来了,如何解决需要传输较大数据的命令呢?对于这样类型的数据,可以对它们利用独立的共享内存来实现,例如TexImage2D。但是,当共享内存大小超过系统的限制时,这种方式就行不通。chromium提供了一种新的机制来解决这个问题。

这个机制就是桶(bucket)机制。其解决问题的原理是,通过共享内存机制来分块传输,而后把分块的数据保存在本地的桶内,从而避免了申请大块的共享内存。前面提到的公共的命令就是用来处理桶相关的数据。当数据传输完成之后,对该数据进行操作的命令就可以执行了。

桶机制也可用来传输string类型的变长数据。接受端首先获取桶内string的长度,然后通过共享内存方式来分块传输,最后合成在自己的桶内。

 ## GPU加速的后端

GPU加速虽然是基于opengles的接口来设计commandbuffer的,但是这不意味着系统的gl的后端库必须是egl/opengles库,这是因为chromium提供了一层转接。

这层转接如何实现的呢?原理其实并不复杂。Chromium首先定义了一组gl相关的函数指针,然后chromium根据设置或者命令行参数来加载相应的库,并从这些库中读取相应的函数地址,并把这些地址赋值给这些函数指针。这样一来,GPU加速部分的代码调用的是这一组函数指针,从而避免直接使用opengles的库。详细代码参考源文件目录” ui/gfx/gl”。

 ## 源代码目录

gpu/

         该目录包含GPU相关的文件,主要包括commandbuffer的实现,工具,GPU涉及的IPC等

gpu/command_buffer

         该目录存放CommandBuffer相关的类,主要包括client端,service端和公共的基础类

gpu/command_buffer/client

         该目录存放GPU客户端所使用到的与CommandBuffer相关的类

gpu/command_buffer/service

         该目录存放GPU进程端所使用到的与CommandBuffer相关和GLES2具体实现相关的类

content/gpu

         该目录存放GPU进程所涉及使用的基础类,包括进程入口函数,IPC,进程和线程管理等相关类

content/common/gpu/

         该目录存放GPU进程使用的与GPU相关的类

content/Renderer/gpu/

         该目录存放Renderer进程使用GPU加速所涉及的类,主要包括IPCchannel, CommandBuffer代理等类

content/browser/gpu/

         该目录存放Browser进程和GPU、Renderer进程交互相关的类,如GPUProcessHost。还包括GPU黑名单的实现

ui/gfx/gl/

         该目录存放与具体的opengl,opengles库相关类,包括根据命令行参数读取所需要的gl的库类型,库的函数地址的读取和管理等等

 

## 参考文献

1.      http://www.chromium.org/developers/design-documents/gpu-command-buffer

2.      http://www.chromium.org/developers/design-documents/gpu-accelerated-compositing-in-chrome

3.      http://www.chromium.org/developers/design-documents/rendering-architecture-diagrams


推荐阅读
  • 带添加按钮的GridView,item的删除事件
    先上图片效果;gridView无数据时显示添加按钮,有数据时,第一格显示添加按钮,后面显示数据:布局文件:addr_manage.xml<?xmlve ... [详细]
  • android listview OnItemClickListener失效原因
    最近在做listview时发现OnItemClickListener失效的问题,经过查找发现是因为button的原因。不仅listitem中存在button会影响OnItemClickListener事件的失效,还会导致单击后listview每个item的背景改变,使得item中的所有有关焦点的事件都失效。本文给出了一个范例来说明这种情况,并提供了解决方法。 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • Android开发实现的计时器功能示例
    本文分享了Android开发实现的计时器功能示例,包括效果图、布局和按钮的使用。通过使用Chronometer控件,可以实现计时器功能。该示例适用于Android平台,供开发者参考。 ... [详细]
  • 本文介绍了pack布局管理器在Perl/Tk中的使用方法及注意事项。通过调用pack()方法,可以控制部件在显示窗口中的位置和大小。同时,本文还提到了在使用pack布局管理器时,应注意将部件分组以便在水平和垂直方向上进行堆放。此外,还介绍了使用Frame部件或Toplevel部件来组织部件在窗口内的方法。最后,本文强调了在使用pack布局管理器时,应避免在中间切换到grid布局管理器,以免造成混乱。 ... [详细]
  • 1简介本文结合数字信号处理课程和Matlab程序设计课程的相关知识,给出了基于Matlab的音乐播放器的总体设计方案,介绍了播放器主要模块的功能,设计与实现方法.我们将该设 ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • 本文介绍了PhysioNet网站提供的生理信号处理工具箱WFDB Toolbox for Matlab的安装和使用方法。通过下载并添加到Matlab路径中或直接在Matlab中输入相关内容,即可完成安装。该工具箱提供了一系列函数,可以方便地处理生理信号数据。详细的安装和使用方法可以参考本文内容。 ... [详细]
  • 推荐系统遇上深度学习(十七)详解推荐系统中的常用评测指标
    原创:石晓文小小挖掘机2018-06-18笔者是一个痴迷于挖掘数据中的价值的学习人,希望在平日的工作学习中,挖掘数据的价值, ... [详细]
  • 深入理解CSS中的margin属性及其应用场景
    本文主要介绍了CSS中的margin属性及其应用场景,包括垂直外边距合并、padding的使用时机、行内替换元素与费替换元素的区别、margin的基线、盒子的物理大小、显示大小、逻辑大小等知识点。通过深入理解这些概念,读者可以更好地掌握margin的用法和原理。同时,文中提供了一些相关的文档和规范供读者参考。 ... [详细]
  • 本文介绍了一款名为TimeSelector的Android日期时间选择器,采用了Material Design风格,可以在Android Studio中通过gradle添加依赖来使用,也可以在Eclipse中下载源码使用。文章详细介绍了TimeSelector的构造方法和参数说明,以及如何使用回调函数来处理选取时间后的操作。同时还提供了示例代码和可选的起始时间和结束时间设置。 ... [详细]
  • 本文详细介绍了Android中的坐标系以及与View相关的方法。首先介绍了Android坐标系和视图坐标系的概念,并通过图示进行了解释。接着提到了View的大小可以超过手机屏幕,并且只有在手机屏幕内才能看到。最后,作者表示将在后续文章中继续探讨与View相关的内容。 ... [详细]
  • Sleuth+zipkin链路追踪SpringCloud微服务的解决方案
    在庞大的微服务群中,随着业务扩展,微服务个数增多,系统调用链路复杂化。Sleuth+zipkin是解决SpringCloud微服务定位和追踪的方案。通过TraceId将不同服务调用的日志串联起来,实现请求链路跟踪。通过Feign调用和Request传递TraceId,将整个调用链路的服务日志归组合并,提供定位和追踪的功能。 ... [详细]
  • Java图形化计算器设计与实现
    本文介绍了使用Java编程语言设计和实现图形化计算器的方法。通过使用swing包和awt包中的组件,作者创建了一个具有按钮监听器和自定义界面尺寸和布局的计算器。文章还分享了在图形化界面设计中的一些心得体会。 ... [详细]
author-avatar
徐青乔府_631
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有