原文地址:blog.tojicode.com/2013/05/how…
原文作者:blog.tojicode.com/
发布时间:2013年5月29日
最近,我在 Twitter/G+ 上对潜在的博客主题进行了一次投票,其中一个被建议的主题就是切换到 Blink 对 Chrome 的 WebGL 实现产生了什么样的影响。我认为这将是一个很好的讨论领域,因为这让我可以比你们大多数人更深入地了解WebGL的工作原理。
如果你还不熟悉这种情况,Chrome最近将渲染引擎从WebKit切换到Blink,Blink是基于WebKit源码的。事实上,我们在Blink诞生的这么早,意味着除了两端的死代码清理之外,两个渲染引擎还没有太大分歧,但即使这么早,Chrome处理WebGL的方式也有一些变化。
在我们讨论这个问题之前,让我们先谈谈当你在javascript中调用gl.whatever时到底会发生什么。如果你问大多数人,甚至是许多 WebGL 开发者,浏览器是如何处理 WebGL 命令的,他们可能会给你一个模糊的模型描述,看起来像这样。
这是基于一些普遍理解的事实。为了安全起见,WebGL命令必须被验证/安全,以确保恶意网页不会使用户的图形驱动或操作系统崩溃。其次,在Windows上,ANGLE经常被用来将GL命令翻译成DirectX命令,以利用传统上更稳定和优化更好的DirectX驱动。
这一切都很好,但这里有很多可能出错的地方。图形驱动程序,特别是在旧系统上,可以是相当不可靠的。事实上,它们与操作系统紧密相连,这意味着有很多机会出现不良行为。由于浏览器希望保护用户免受意外的驱动程序行为和试图从驱动程序中挑起不良行为的恶意代码的影响,Chrome沙盒将所有驱动程序的交互锁定在一个锁定的GPU进程中。这让我们可以仔细控制我们向GPU发送的命令,如果GPU进程出现问题,不会导致整个浏览器崩溃。
所以更新我们的模型以考虑到这一点,我们得到的图看起来更像这样。
所以... ...这很接近真实的情况,对吧?对吧?
现实情况是,和往常一样,相当复杂。让我们来看看一个真正快速而又简单的图表,该图表显示了在 Chrome 原始 WebKit 后端处理 WebGL 调用时涉及的实际类/文件。
只是比第一张图更复杂一点,对吧?虽然技术上并不完全准确,但它显示了一个命令通过 WebGL 管道前半部分的基本流程。是的,这是正确的。这只是其中的一半。我省略了整个GPU流程,它和这张图一样复杂。我也跳过了资源对象的实现,比如纹理和缓冲区,所有这些资源对象都增加了自己的类。
那为什么要写这么多层代码呢?这是不是有点过分了?
好吧,由于WebKit被许多不同的浏览器使用,而不仅仅是Chrome浏览器,所以对于任何这样的接口,都需要一定程度的抽象和分离。有很多代码是由WebKit核心处理的,但任何平台或浏览器特定的东西都会被推迟到特定端口的实现代码(这里用Chromium标志表示)。这对于实现WebKit所享有的 "运行在任何东西上 "的灵活性是必要的,但却带来了复杂性。
让我们快速浏览一下这些步骤的作用。
V8WebGLRenderingContext是由WebGL接口IDL自动生成的。它将Javascript虚拟机(V8)中来往的数据整理成更便于用户使用的格式,然后传递给...
WebGLRenderingContext。这是大多数WebGL特定逻辑发生的地方。WebGL规范在OpenGL ES 2.0规范之外还有许多额外的限制,这些验证都在这里完成。一旦数据干净利落并获得 WebGL 批准,我们就将其交给......
GraphicsContext3D。浏览器使用OpenGL不仅仅是为了WebGL。很多工作都是为了让浏览器在每个页面上尽可能有效地利用GPU,使滚动更流畅、渲染更快速、交互更敏捷。然而,我们并不希望浏览器的所有内部代码都受到与 WebGL 相同的限制。这个类向WebKit代码库中任何需要执行GPU工作的部分暴露了一个非常接近OpenGL ES 2.0的API(偶尔会通过Extensions3D来处理扩展),但是由于WebKit必须在多个平台上工作,这个类是相当抽象的。它在不同的平台上有不同的后端,但在Chrome的情况下,它是由...
GraphicsContext3DChromium/GraphicsContext3DPrivate。这两个类构成了Chrome对WebKit的GPU接口的实现。在某些平台上,这可能是实际的GPU调用的地方,但在Chrome的情况下,我们希望利用沙盒化的GPU过程。因此,这个类主要是将GL命令直接反馈给...
WebGraphicsContext3D。这个类通过一个 "命令缓冲区 "促进与GPU进程的通信,该缓冲区将GL命令打包成安全的小内存包,通过共享内存推送到进程边界。实际上,这是一个谎言。这个类并没有直接做到这一点,但你真的希望图表更复杂吗?对于我们的需求来说,它已经足够准确了。
大多数非WebKit Chrome的代码会直接使用这个类而不是GraphicsContext3D,因为一旦你进入Chrome特定的代码,就不需要抽象了。
最后,所有的东西都会在GPU Process中结束,它本身相当复杂,但我不会在这里深入介绍。在从共享内存中解包GL命令后,它将进行另一轮验证,以确保它得到了有效的指令(GPU进程的政策是不信任与它通信的外部进程)。一旦它对一切安全感到满意,它最终会进行实际的驱动调用,在某些情况下,它实际上变成了一个 ANGLE 调用,通过 DirectX 重定向。
呼! 我打赌你从来没有意识到你的 WebGL 调用在到达你的显卡之前有多么的折腾! 但所有这些都是Chrome基于WebKit时的工作方式。回到最初的问题。Blink是如何改变这个过程的?
让我们看看今天Blink中同样的数据流。
依然复杂,但明显更直接了。具体来说,这里发生的事情是,我们把WebKit为了抽象而需要拆分的地方,合并成了一个类。GraphicsContext3DChromium和GraphicsContext3DPrivate的代码现在是GraphicsContext3D的一部分。同样,Extensions3DChromium也是如此,结果是一整层的抽象融化了。
需要注意的是:实际执行的代码在Blink和WebKit版本之间几乎是一样的。唯一真正发生变化的是,我们将过去特定于 port 的代码合并到了基类中,并花时间去掉了那些 Chrome 浏览器无论如何都不会碰到的死代码路径。这意味着对于 Chrome 开发者来说,需要处理的文件更少,需要绕过的抽象也更少,但在性能方面可能会产生很小的影响(我们取消了几个虚拟函数调用,但仅此而已)。
最后这样的改动是为了加快开发速度,对最终用户几乎没有影响,但这非常符合Blink简化代码和加快迭代的目标。最终我们可能会发现这种重构带来的优化机会,但现在都是为了清理。
不过除了实现简化之外,我预计转用Blink对WebGL的发展影响不大。苹果并没有阻止WebGL的功能或类似的东西,而且几乎所有的WebGL实现者在什么应该和不应该进入API的问题上都是一致的。我们对WebGL的发展方向已经非常满意,所以不要指望因为Blink而推动任何剧烈的变化。
不过,有一个面向用户的、与Blink相关的变化正在进行中。与Blink关于CSS和Javascript前缀的政策保持一致,当我们暴露新的扩展时,我们将不再给它们加前缀(所以扩展名前面不再有 "WEBKIT_")。取而代之的是,我们将把尚未被社区批准的扩展(称为 "草案 "扩展)隐藏在一个标志后面。这将允许开发人员继续试验即将到来的扩展,而不必担心生产站点会依赖它们,如果在扩展被批准之前规范发生变化,就会产生问题。
所以你有了它。Blink让我们稍微简化了WebGL的实现 它的前缀政策将改变开发者尝试新扩展的方式 但除此之外,它将继续是你所熟知和喜爱的WebGL。
希望你喜欢这堂解剖课
【编辑:想看更多? 请看第二部分】