Chromium Graphics: GPU客户端之间同步机制的原理和实现分析-Part I

摘要:Chromium中GPU进程架构导致多个GPU客户端会同时访问GPU服务,而多个GPU客户端可能存在数据依赖关系,例如渲染WebGL页面时,因此需要提供一种同步机制保证GPU操作的先后次序。本文讨论的就是多进程架构下GPU客户端之间的同步问题,以及同步点(SyncPoint)机制的基本原理。

GPU进程架构等基本概念

我们知道,Chromium是一个多进程架构的软件系统。出于安全和稳定性方面的考虑,Chromium有个专门的进程(或者线程)和GPU设备进行交互,执行GL操作,也就是说,任何一条GL命令都必须经由这个进程处理后才提交给GPU驱动,这个进程就是GPU进程。Renderer进程或者Browser进程需要通过IPC才能与GPU进程交互,告诉GPU进程需要执行哪些GL命令。在这个过程中,Renderer进程或Browser进程是GPU进程的客户端,而GPU进程本身扮演着服务端的角色。

GPU客户端和服务端之间GL命令传输是通过命令缓冲区(CommandBuffer)完成的。CommandBuffer是Chromium为解决多进程架构下高效传输数据而设计的,缓冲区使用共享内存存储客户端向服务器端发起的GL命令,GPU客户端发起的每条GL命令,命令名和参数都会被序列化为字符串存储在命令行缓冲区中。当客户端需要将存储在缓冲区中的所有GL命令发送给GPU服务端请求执行时,客户端会向服务端发送GpuCommandBufferMsg_AsyncFlush消息,服务器端收到这条消息后会根据指定的偏移从CommandBuffer中将GL命令反序列化。

在Chromium中,页面的渲染和合成过程都启用了GPU硬件加速,任何一个需要GPU加速的进程都是GPU进程的客户端,换句话说,Renderer进程是GPU客户端,因为它需要请求GPU进程绘制和合成页面的内容,Browser进程也是GPU客户端,因为Browser需要将页面的内容与地址栏等元素进行最终的合成,并显示在屏幕上。

不同GPU客户端是通过mailbox机制进行texture共享的,简单的说,mailbox机制就是给每个texture生成唯一标识,并由GPU进程统一管理名标识和texture之间的映射关系。

GPU客户端之间的同步问题

从上述描述不难看出,GPU进程需要处理来自多个GPU客户端的请求,并且这些GPU客户端可能存在纹理(Texture)数据依赖关系。

下面以Android平台上渲染WebGL页面http://get.webgl.org 为例,说明为什么不同GPU客户端会存在数据依赖关系。

首先,Browser进程是一个GPU客户端,它创建了一个Browser端的合成器(Compositor)请求GPU进程将页面的内容和地址栏等UI元素(如果有)进行最终的合成,并将其渲染到SurfaceView上。Renderer进程也是GPU客户端,它也会创建一个Renderer端的合成器用于页面的合成,而且这个客户端还包含了两个独立的3D上下文,一个用于页面的渲染,另一个用于WebGL的渲染。

其次,在Android平台上,默认启用了委托模式(DelegatedRenderer)的渲染器,因此,Renderer端合成器管理的所有GPU资源(包括WebGL)都会转交给Browser端的合成器,再由Browser端合成器进行统一的合成,当最终的合成操作完成之后,Browser端合成器则会告诉Renderer端资源使用完毕,可以安全删除了。

最后,再来看看WebGL的渲染过程。在硬件加速的页面渲染机制中,页面的内容是由多个渲染层(RenderLayer)构成的,每个渲染层的存储后端对应一个Texture,WebGL正是这样一个渲染层,它具有一个独立的Texture存储后端。在渲染每一帧内容时,Renderer进程会请求GPU进程创建一个新的Texture来存放WebGL的渲染结果,并通过Framebuffer对象将WebGL渲染到这个Texture中。待 WebGL命令完毕后,Renderer端的合成器再将这个Texture以资源形式转交给Browser端的合成器并将其渲染到SurfaceView的指定坐标上。当Browser端合成器完成WebGL的合成之后,会通知Renderer进程可以将这个Texture删除。

那么,从上面的描述中可以推断出整个过程存在哪些问题呢?

第一,Renderer端的合成器和Browser端合成器存在数据依赖关系,是生产者-消费者的关系,即Renderer端的WebGL上下文生成Texture内容,Browser端合成器使用该内容;

第二,WebGL上下文和Browser端合成器存在同步问题。由于所有的GL命令都是在同一线程中执行,而3D上下文是GPU线程的调度基本单位,也就是只有同一个3D上下文中GL命令才能按照顺序逐条执行的。一方面,不同GPU客户端可能运行在不同的进程或者线程中,另一方面,同一GPU客户端的不同3D上下文可能运行在不同的线程中,例如Renderer进程的合成器运行在一个单独的线程中,而WebGL运行在Renderer进程的主线程中。那么显然,不同3D上下文中GL命令执行不会按照指定的次序关系执行,这里就引申出一个问题,对于WebGL页面渲染来说,如何保证:

  • 只有当WebGL上下文的GL命令执行完毕后,Browser端合成器才能使用;
  • 只有当Browser端合成器使用完WebGL的Texture后,WebGL上下文才能安全删除;

这就是GPU客户端之间的同步问题,本文接下来将重点讨论Chromium是如何解决这个问题的。

同步点机制的基本原理

Chromium通过GL扩展接口设计了一套同步机制解决不同GPU客户端之间的同步问题,这套机制必须满足两个条件:

第一,上下文A可以等待上下文B执行完GL命令后再执行后续的GL命令;

第二,上下文A中的这种等待必须是非阻塞的,也就是说GPU客户端代码的执行不能被阻塞;

根据gpu/gles2/extensions/GL_CHROMIUM_sync_point.text文件所述,同步点机制定义了两个特定于Chromium的GL扩展接口:

        uint InsertSyncPointCHROMIUM()
        void WaitSyncPointCHROMIUM(uint sync_point)

InsertSyncPointCHROMIUM在当前上下文中创建一个同步点并将其插入到命令流中,这个同步点起到一个防护墙的作用,当这个同步点之前的命令都已经提交到服务器,或者上下文被销毁时,会向该同步点发个信号。返回同步点的标识符。收到信号后,这个同步点会被删除点。在同一个服务器上同步点标识符在所有上下文中是唯一的,包括同一共享组的上下文。

WaitSyncPointCHROMIUM导致当前上下文暂停提交GL命令,直到指定同步点收到信号,被实现为服务端的等待。参数sync_point为InsertSyncPointCHROMIUM返回的同步点标识符。如果sync_point参数无效,这个命令相当于no-op操作并且不会报错。

以上文档化的描述读起来有些晦涩难懂,下面通过一个简化的例子更直观地说明SyncPoint在Chromium中的运行原理:

假设有两个上下文A和B,它们可能在不同的GPU客户端中,但属于同一个共享组(ShareGroup),GPU客户端代码中通过调用InsertSyncPointCHROMIUM在上下文A的命令流中插入一个同步点sp,而在上下文B中,调用WaitSyncPointCHROMIUM等待同步点sp,最终在GPU服务端执行GL命令的顺序为,只有当上下文A中同步点sp之前的GL命令A1,A2和A3执行完毕后,才会执行上下文B中的GL命令B3。

更进一步地说,上下文B中调用WaitSyncPointCHROMIUM(sp),实际上是告诉GPU服务端停止向GPU设备提交上下文B后续的GL命令,取而代之的是:

  • 如果此时上下文A的同步点sp之前的GL命令都已经执行完毕,即同步点sp收到信号,已经从被删除了,那么可以忽略WaitSyncPointCHROMIUM了,继续执行上下文B中后续的GL命令;
  • 如果此时上下文A的同步点sp之前的GL命令尚未执行,那么取而代之的是将等待上下文A中sp点之前的GL命令执行完毕。这个等待发生在GPU服务端的,不会阻塞GPU客户端后续代码的运行(如Renderer进行的运行)。

综上所述,同步点机制允许客户端设定不同上下文之间GL命令执行的次序,上下文B等待上下文A的同步点实际上是保证A中同步点之前的命令在B中后续命令之前执行。

未完待续...下节将从Chromium源代码中解读同步点机制是如何实现的

时间: 2024-10-17 03:33:45

Chromium Graphics: GPU客户端之间同步机制的原理和实现分析-Part I的相关文章

Chromium Graphics: GPU客户端之间同步机制的原理和实现分析-Part II

摘要:Part I分析了GPU客户端之间存在的同步问题,以及Chromium的GL扩展同步点机制的基本原理.本文将源代码的角度剖析同步点(SyncPoint)机制的实现方式.同步点机制的实现主要涉及到是如何跨进程实现两个GL扩展接口InsertSyncPointCHROMIUM和WaitSyncPointCHROMIUM的实现方式,以及如何实现GPU服务端的同步点等待. GPU客户端 GPU客户端将所有的GL命令都封装在GLES2Implementation中,GLES2Implementati

Socket(套接字)在服务器端和客户端之间的基本工作原理

Socket之间的连接过程主要可以概括为以下三步: 服务器建立监听:客户端初始化Socket动态库后创建套接字,然后指定客户端Socket的地址,循环绑定Socket直至成功,然后开始建立监听,此时客户端处于等待状态,实时监控网络状态: 客户端提出请求:客户端的Socket向服务器端提出连接请求,此时客户端描述出它所要连接的Socket,指出要连接的Socket的相关属性,然后向服务器端Socket提出请求: 连接确认并建立:当服务器端套接字监听到来自客户端的连接请求之后,立即响应请求并建立一个

使用rsync在linux(服务端)与windows(客户端)之间同步

说明: 1.RsyncServer服务端 系统:CentOS 6.8 IP地址:192.168.247.141 2.Rsync客户端 系统:Windows10 实现目的: Rsync客户端同步服务端/data/test下的文件到E/test下 一 .在linux上安装rsync 1.#rpm -qa|grep rsync yum install rsync -y 2.vim /etc/rsyncd.conf uid=root gid=root max connections=10 log fil

Chromium Graphics: 再谈Chromium WebView硬件渲染模式的演进

摘要:从Android KitKat系统第一个采用Chromium内核的WebView开始,Android WebView一直在持续演进中,自Chromium M38开始,WebView在硬件渲染模式方面发生了较大的变化,最明显的变化莫过于WebGL的支持以及ubercompositor的使用,同时为了吻合Android L的渲染模型变化,DrawGL函数是在Android系统的渲染线程中执行的. Android 4.4系统WebView的硬件渲染 对于Chromium WebView来说,首先

Linux 内核的同步机制,第 1 部分 + 第二部分(转)

http://blog.csdn.net/jk198310/article/details/9264721  原文地址: Linux 内核的同步机制,第 1 部分 一. 引言 在现代操作系统里,同一时间可能有多个内核执行流在执行,因此内核其实象多进程多线程编程一样也需要一些同步机制来同步各执行单元对共享数据的访问.尤其是在多处理器系统上,更需要一些同步机制来同步不同处理器上的执行单元对共享的数据的访问.在主流的Linux内核中包含了几乎所有现代的操作系统具有的同步机制,这些同步机制包括:原子操作

多进程间通信方式和多线程同步机制总结

多进程之间通信方式: 文件映射:本地之间 共享内存:本地之间 匿名管道:本地之间 命名管道:跨服务器 邮件槽:一对多的传输数据,通常通过网络向一台Windows机器传输 剪切板:本地之间 socket:跨服务器 多线程之间通信方式: 全局变量 自定义消息响应 多线程之间同步机制:           临界区:不可以跨进程,忘记解锁会无限等待,要么存在要么没有,多线程访问独占性共享资源 互斥量:可以跨进程,忘记解锁会自动释放,要么存在要么没有 事件:又叫线程触发器,不可以跨进程,要么存在要么没有,

Thread同步机制比较

ThreadLocal和线程同步机制相比有什么优势呢?ThreadLocal和线程同步机制都是为了解决多线程中相同变量的访问冲突问题. 在同步机制中,通过对象的锁机制保证同一时间只有一个线程访问变量.这时该变量是多个线程共享的,使用同步机制要求程序慎密地分析什么时候对变量进行读写,什么时候需要锁定某个对象,什么时候释放对象锁等繁杂的问题,程序设计和编写难度相对较大. 而ThreadLocal则从另一个角度来解决多线程的并发访问.ThreadLocal会为每一个线程提供一个独立的变量副本,从而隔离

Chromium硬件加速渲染的GPU数据上传机制分析

在Chromium中,WebGL端.Render端和Browser端通过命令缓冲区将GPU命令发送给GPU进程执行.GPU命令携带的简单参数也通过命令缓冲区发送给GPU进程,但是复杂参数,例如纹理数据,有可能太大以致命令缓冲区无法容纳,因此需要通过其它机制传递给GPU进程.本文接下来就主要以纹理数据上传为例,分析WebGL端.Render端和Browser端将GPU命令数据传递给GPU进程的机制. 老罗的新浪微博:http://weibo.com/shengyangluo,欢迎关注! WebGL

Android中的GraphicBuffer同步机制-Fence

Fence是一种同步机制,在Android里主要用于图形系统中GraphicBuffer的同步.那它和已有同步机制相比有什么特点呢?它主要被用来处理跨硬件的情况,尤其是CPU,GPU和HWC之间的同步,另外它还可以用于多个时间点之间的同步.GPU编程和纯CPU编程一个很大的不同是它是异步的,也就是说当我们调用GL command返回时这条命令并不一定完成了,只是把这个命令放在本地的command buffer里.具体什么时候这条GL command被真正执行完毕CPU是不知道的,除非CPU使用g