【问题标题】:WebGL how to avoid long shader compile stalling a tabWebGL如何避免长着色器编译停止选项卡
【发布时间】:2019-05-01 16:05:00
【问题描述】:

我有一个巨大的着色器,它需要一分钟多的时间来编译,它在整个过程中完全停止了整个浏览器。据我所知,着色器编译不能异步进行,因此您可以在等待编译完成时运行其他 WebGL 命令。

我已经尝试了以下方法:

  • 暂时不要使用特定的着色器 - 这不起作用,因为大多数其他 WebGL 命令将等待它完成,即使该着色器程序从未激活过
  • 使用另一个上下文 - 与上面相同,但即使来自另一个上下文的 WebGL 命令也会导致停顿
  • 在 web worker 中使用 OffscreenCanvas - 这也不能避免停顿,即使它在 worker 中,它也会停顿整个浏览器。即使我在命令链接程序后等待几分钟以发出任何其他 WebGL 命令,浏览器也会停止(好像在那段时间没有发生任何事情)

另一个问题是它有时会导致 WebGL 崩溃(上下文丢失),这会导致页面(或工作线程)上的所有上下文崩溃。

有什么办法可以避免浏览器卡住吗?

我可以将我的着色器拆分为多个部分并分别编译吗?

这就是我的程序初始化的样子,可以以某种方式更改吗?

let vertexShader = gl.createShader(gl.VERTEX_SHADER);
let fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
let program = gl.createProgram();

gl.shaderSource(vertexShader, vertexSource);
gl.shaderSource(fragmentShader, fragmentSource);

gl.compileShader(vertexShader);
gl.compileShader(fragmentShader);

gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);

gl.linkProgram(program);

gl.useProgram(program);

let status = gl.getProgramParameter(program, gl.LINK_STATUS);
let programLog = gl.getProgramInfoLog(program);

在调用 linkProgram 后等待几分钟甚至在工作人员中也无济于事。

最后要注意的是:我可以有例如使用不受此影响的 OpenGL 运行的 windows 游戏(游戏正在运行,我开始在浏览器中编译此着色器,并且游戏在浏览器停止时继续运行正常)

【问题讨论】:

  • 您是在拨打gl.linkProgram之后再拨打gl.flush然后等待的吗?
  • @gman 调用gl.flush 会立即导致停顿。我不明白为什么它在网络工作者中完成时会冻结整个浏览器。所有 WebGL 上下文是否最终都为选项卡/浏览器使用相同的上下文?如果我会遇到相同的编译时间,例如C/C++ 应用程序会影响其他线程吗? (我可能会尝试,但它肯定不会影响其他应用程序,所以我希望在不同线程中创建的两个 OpenGL 上下文不应该以这种方式相互影响)。

标签: webgl webgl2


【解决方案1】:

更新

Chromium 添加了KHR_parallel_shader_compile 扩展,允许您查询着色器是否已完成编译。

不幸的是,截至 2021 年 1 月,只有 Chromium(Chrome/Edge/Brave/etc...)实施了它


原答案

没有好的解决办法。

Windows 上的浏览​​器使用 DirectX,因为 OpenGL 在许多机器上默认不提供,而且浏览器所需的许多其他功能与 OpenGL 不兼容。

DirectX 编译着色器需要很长时间。只有微软可以解决这个问题。 Microsoft 提供了 HLSL 着色器编译器的源代码,但它仅适用于 DX12。

有些人建议允许网页提供二进制着色器,但由于两个非常重要的原因,这永远不会发生

  1. 它们不便携

    网页必须提供 100 或 1000 种二进制着色器的变体。一种适用于每种类型的 GPU * 每种类型的驱动程序 * 每个平台(iOS、Android、PI、Mac、Windows、Linux、Fire 等)。网页应该在任何地方加载,因此着色器二进制文件不是网络的解决方案。

  2. 这将是一个巨大的安全问题。

    让用户下载随机二进制 blob 并交给 OS/GPU 执行将成为漏洞利用的巨大来源。1

请注意,某些浏览器(尤其是 Chrome)会在后台本地缓存着色器二进制文件,但这无助于首次编译。

所以目前基本上没有解决办法。您可以制作更简单的着色器或一次编译更少的着色器。人们要求使用异步扩展来编译着色器,但没有任何动静。

这是 2 年前的帖子 https://www.khronos.org/webgl/public-mailing-list/public_webgl/1702/msg00039.php

只是个人意见,但我猜测异步扩展没有太多动作的原因是实现起来比听起来要多得多,而且存在大量具有复杂着色器的网站并且似乎可以工作。


1您作为文本 GLSL 传递给 WebGL 的着色器由浏览器编译,检查各种问题,如果违反任何 WebGL 规则则拒绝,然后将它们重新写入插入错误解决方法,重写变量名,添加钳位指令,有时展开循环,确保您不会使驱动程序崩溃的各种事情是安全的。您可以使用WEBGL_debug_shaders 扩展来查看实际发送给驱动程序的着色器。

二进制着色器是您提供给驱动程序的 blob,您没有机会检查它或验证它没有做坏事,因为它是驱动程序专有的二进制文件。没有关于其中内容、格式的文档,它们可以随每个 GPU 和每个驱动程序而改变。你只需要相信司机。司机不靠谱。最重要的是,它是在您的机器上执行的不受信任的代码。这与下载随机 .exe 并执行它们没有什么不同,因此不会发生。

对于 WebGPU,不,WebGL 没有更多的安全风险。即使它使用二进制格式,二进制格式也将用于 WebGPU 本身,而不是驱动程序。 WebGPU 将读取二进制文件,检查是否遵循所有规则,然后生成与用户 GPU 匹配的着色器。生成的着色器可以是 GLSL、HLSL、MetalSL、SPIR-V,任何可行的方法,但与 WebGL 类似,它只会在验证所有规则都遵循之后才编写着色器,然后它编写的着色器,就像 WebGL 一样,将包括变通方法、钳位以及其他需要使着色器安全的东西。请注意,截至今天 2018 年 11 月 30 日,尚未确定 WebGPU 的着色器格式是什么。 Google 和 Mozilla 正在推动 SPIR-V 的二进制子集Apple and Microsoft are pushing for WHLSL,这是文本中 HLSL 的变体

请注意,当浏览器显示“RATS!WebGL it a snag”时,并不意味着驱动程序崩溃了。相反,它几乎总是意味着 GPU 因花费太长时间而被重置。在 Chrome 中(不确定其他浏览器),当 Chrome 要求 GPU(通过驱动程序)做某事时,它会启动一个计时器。如果 GPU 没有在 2-5 秒内完成(不确定实际超时),那么 Chrome 将终止 GPU 进程。这包括编译着色器,因为 DirectX 需要花费最多的时间来编译,这就是 DirectX 上出现此问题最多的原因。

在 Windows 上,即使 Chrome 没有这样做,Windows 也会这样做。这主要是因为大多数 GPU(可能都在 2018 年)不能像 CPU 那样进行多任务处理。这意味着如果你给他们 30 分钟的工作时间,他们会在 30 分钟内不间断地完成这件事,这基本上会冻结你的机器,因为你的机器需要 GPU 来绘制应用程序窗口等。过去 Windows 解决了这个问题,就像Chrome,如果某些事情花费了太长时间,则重置 GPU。过去,Linux 和 Mac 只会在这 30 分钟内冻结或使操作系统崩溃,因为操作系统希望能够绘制图形而不能。在过去 8 年的某个时候,Mac 和 Linux 在这方面做得更好。在任何情况下,Chrome 都需要尝试主动,以便使用自己的计时器并在时间过长时将其终止。

【讨论】:

  • 我知道 WebGL 不支持二进制着色器,但它代表了什么样的安全风险? (除了崩溃或冻结 WebGL,因为我也可以使用文本源代码来做到这一点)。在为此寻找解决方案的过程中,我偶然发现了旨在使用一些中间着色器表示的 WebGPU,如果您熟悉它,这是否也会产生一些安全风险? (一些快速搜索告诉我 DirectX 对 HLSL 和 Vulcan 使用了类似的东西,但我从未使用过这些 API,所以我不太了解)
  • 添加了更多细节来回答
  • 感谢您的详细回复,并提示WEBGL_debug_shaders分机。在调用compileShader 并在任何地方插入gl.flush() 后浏览器在linkProgram 大约一分钟后冻结后立即可用翻译的HLSL 源代码,所以我猜此时HLSL 编译器花费的时间太长(在CPU 上,或者在整个操作系统上如果 GPU 不能多任务处理会被冻结),如果我得到上下文丢失,那是因为编译/链接的 GPU 部分花费了太长时间?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-05-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多