Chromium Graphics: 3D上下文及其虚拟化(Virtualization) - Part II

摘要:Part I介绍了OpenGL上下文和绘制表面等基本概念,以及Chromium为什么需要多个3D上下文。本文将继续这个话题,探讨Chromium为什么需要引入虚拟3D上下文,以及虚拟上下文之间切换有何不同。

多个3D上下文的限制

Chromium需要使用多个3D上下文,并且这些上下文能够共享资源。然而,目前图形驱动对多个3D上下文的支持存在不同程度的问题,尤其是在移动设备上,例如(参见http://crbug.com/155557 ):

  • 有些驱动一旦使用多个上下文就会暴露这样或那样的问题;
  • 有些驱动在共享资源的多个上下文之间切换时很慢;
  • 有些驱动限制了多个上下文数量;
  • 有些驱动在资源共享方面存在问题,例如在一个上下文中更新了一个资源,但另一个上下文却得不到这个更新。

虚拟的3D上下文

对存在上述问题的GPU设备,Chromium引入了虚拟上下文的概念,其主要思路是尽可能避免创建真实的3D上下文,通过虚拟化3D上下文使得多个上下文可共享一个真实的上下文,而虚拟上下文的切换不一定不会导致实际上下文的切换,如此不仅减少了真实的上下文数量,而且有效地避免了上下文切换的性能开销等问题。

Chromium只会对存在问题的GPU设备采用创建虚拟上下文的方法,也就说,对于多上下文支持良好的GPU设备,是采用虚拟上下文的。文件gpu/config/gpu_driver_bug_list_json.cc列举所有可能有问题的GPU驱动,包括上述多上下文支持的问题,Chromium运行时读取这个列表并与当前系统的GPU驱动进行匹配,如果匹配成功并且包含特性use_virtualized_gl_contexts时,那么Chromium则会使用虚拟化的上下文来规避GPU驱动可能存在的问题。

GPU线程收到来自客户端(可能是Browser进程,也可能是Renderer进程)的上下文创建请求后,会请求GPU驱动创建上下文实例:

  1. 如果GPU驱动能够支持多上下文时,GPU线程会为每个请求都创建一个真实的上下文;
  2. 如果GPU驱动不能支持多上下文时, GPU线程则会为每个请求创建一个虚拟的上下文;

对于情况1,GPU线程直接创建平台相关的上下文。需要特别说明的是,GPU线程中所有创建的上下文都属于同一个共享组(sharegroup)。同一共享组中所有上下文之间资源是可以共享的,共享意味着它们使用的是同一个名字空间,任何一个上下文创建的Texture都可以被其他上下文所使用。可共享的资源包括Texture,Buffer对象和GLSL对象等。因此,Browser端的Compositor可直接访问WebGL上下文中的Texture,用来最终的屏幕合成。

对于情况2,GPU线程创建的是虚拟上下文,并且所有的虚拟上下文都将共享同一个真实的上下文。

不论是真实上下文,还是虚拟上下文,必须与一个与其兼容的渲染表面(Drawing Surface)才能被切换成为“当前”上下文,启动OpenGL的渲染流水线。

渲染表面和上下文的切换

GLX和EGL规范中都明确定义了,要让GLXContext或EGLContext成为“当前”的上下文还需要指定渲染表面。Chromium定义了两类渲染表面:

  • 屏上(onscreen)渲染表面:每个onscreen的渲染表面都是窗口系统的一个窗口,根据窗口ID或者句柄创建而来,具有前后双缓冲区,通过交换缓冲区将渲染结果呈现在屏幕上的窗口中。Chromium只会为Browser进程端的Compositor创建这个渲染表面作为合成表面(compositingsurface);
  • 离屏(offscreen)渲染表面:只有后缓冲区,内容在屏幕不可见。以WebGL为例,Chromium通过Framebuffer对象将WebGL渲染到一个Texture,而WebGL上下文所使用的渲染表面正是一个构建在PBuffer上的offscreen渲染表面。

有了渲染表面,便可以将一个上下文切换成为“当前”上下文。真实上下文之间的切换,实际是OpenGL状态机之间的切换,而虚拟上下文的切换,Chromium是不会触发真实上下文的切换,尽管渲染表面是从onscreen类型切换到offscreen类型的。下图展示的就是调用makeCurrent切换真实上下文的情形。


前面提到,GPU线程收到上下文创建请求后,创建虚拟上下文之前,会首先尝试从共享组(share group)获取一个真实上下文,如果没有,则需要创建这样一个上下文并添加到共享组中,再创建一个构建在这个真实上下文之上的虚拟上下文,然后以渲染表面初始化这个虚拟上下文,这里强调一下,上下文需要一个与其兼容的渲染表面才能成为能够执行GL命令的“当前”上下文。

  • 如果GPU线程收来自Browser进程端的请求,要为Compositor创建虚拟上下文,那么这个渲染表面是一个onscreen渲染表面(从窗口ID创建而来);
  • 如果GPU线程收到来自Render进程端的请求,要为WebGL创建虚拟上下文,那么这个渲染表面是一个offscreen渲染表面(Pbuffer)。

创建上下文之后,GPU线程将交替执行不同上下文中的GL命令,这就意味着GPU线程能够在虚拟上下文之间进行切换。那么虚拟上下文的切换有什么不同呢?

第一,因为只有真实上下文才会拥有一个OpenGL状态机,所以在使用虚拟上下文的情况下,GPU线程只有一个OpenGL状态机,而这个状态机被不同目的的虚拟上下文(如Compositor,WebGL等)所复用。为了确保来回切换时能够恢复上一次的OpenGL状态,Chromium为每个虚拟上下文都提供了一个状态恢复器用以OpenGL状态的恢复。OpenGL的状态包括,

  • Framebuffer对象的绑定
  • 所有Texture单元的绑定
  • 顶点属性
  • Buffer对象和RenderBuffer的绑定
  • OpenGL全局状态

第二,虚拟上下文的切换只是逻辑上的上下文切换,并不会导致真实上下文的切换(因为只有一个真实上下文),尽管Compositor和WebGL上下文使用的是不同的渲染表面,但仍然不会因渲染表面的不同而导致上下文的切换。具体的来说,假如当前GPU线程已经工作在Compositor的虚拟上下文中,使用的是onscreen渲染表面,此时GPU线程需要切换到WebGL上下文去执行GL命令,而WebGL虚拟上下文时使用的offscreen渲染表面(Pbuffer),即便是两者具有不同类型的渲染表面,也不会导致真实上下文的切换。因为对于WebGL的离屏渲染方式来说,它是通过Framebuffer对象将内容渲染到一个Texture上,所以指定的渲染表面既可以是onscreen,也可以是offscreen的,只是对于onscreen的情况来说,使用的仅仅是它的后缓冲区,最终的内容还是在Texture中,所以不用关心用的是哪类渲染表面。下图描述的就是虚拟上下文的情形:


那么,在哪些情况下虚拟上下文的切换才会导致真实上下文的切换呢?

  •  第一次切换到Browser进程端的Compositor虚拟上下文时,此时整个GPU线程还没有绑定一个有效的“当前”上下文,需要执行真实上下文的切换,保证GPU线程有个共享的OpenGL状态机;
  • 当两个不在同一共享组的虚拟上下文切换时,表面这两个虚拟上下文具有对应的真实上下文。
  • 当两个虚拟上下文同时需要在两个不同的onscreen表面切换时,不论是否在同一个共享组中。

目前Chromium的实现中,实际上只有情况1才会发生,而情况2和3只是从代码逻辑中的推理而得出来的。

未完待续...下节将从Chromium源码解读上下文以及虚拟化是如何实现的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值