WebGL 如何避免长时间着色器编译导致选项卡停顿

2023-12-24

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

我已经尝试过以下操作:

  • 在一段时间内不要使用该特定着色器- 这不起作用,因为大多数其他 WebGL 命令将等待它完成,即使该着色器程序从未激活
  • 使用另一个上下文- 与上面相同,但即使来自另一个上下文的 WebGL 命令也会导致停顿
  • 在 Web Worker 中使用 OffscreenCanvas- 这也不能避免停顿,即使它在工作线程中,它也会停顿整个浏览器。即使我在命令链接程序后等待几分钟以发出任何其他 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 游戏不受此影响(游戏正在运行,我开始在浏览器中编译此着色器,游戏在浏览器停止时继续正常运行)


Update

铬添加了KHR_parallel_shader_compile https://www.khronos.org/registry/webgl/extensions/KHR_parallel_shader_compile/扩展允许您查询着色器是否完成编译。

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


原答案

没有好的解决办法。

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

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

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

  1. 它们不便于携带

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

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

    Having users download random binary blobs that are given to the OS/GPU to execute would be huge source for exploits.1

请注意,某些浏览器(特别是 Chrome)会在幕后本地缓存着色器二进制文件,但这对首次编译没有帮助。

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

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

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


1The shaders you pass to WebGL as text GLSL are compiled by the browser, checked for all kinds of issues, rejected if any of the WebGL rules are broken, they are then re-written to be safe with bug workarounds inserted, variable names re-written, clamping instructions added, sometimes loops unrolled, all kinds of things to make sure you can't crash the driver. You can use WEBGL_debug_shaders extension to see the shader that's actually sent to the driver.

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

至于WebGPU,不,WebGL 不再有安全风险。即使它使用二进制格式,该二进制格式也适用于 WebGPU 本身,而不是驱动程序。 WebGPU 将读取二进制文件,检查是否遵循所有规则,然后生成与用户 GPU 匹配的着色器。生成的着色器可以是 GLSL、HLSL、MetalSL、SPIR-V,无论什么都可以,但与 WebGL 类似,只有在验证所有规则都遵循后,它才会编写着色器,然后它编写的着色器,就像 WebGL 一样,将包括解决方法、钳位以及任何其他需要使着色器安全的事情。请注意,截至今天 2018 年 11 月 30 日,WebGPU 的着色器格式尚未确定。 Google 和 Mozilla 正在推动 SPIR-V 的二进制子集,苹果和微软正在推动 WHLSL https://webkit.org/blog/8482/web-high-level-shading-language/,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 需要尝试主动行动,因此它会使用自己的计时器,并在时间过长的情况下杀死它们。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

WebGL 如何避免长时间着色器编译导致选项卡停顿 的相关文章

  • 未捕获的类型错误:无法解析模块说明符“三/示例/jsm/loaders/GLTFLoader.js”

    我很难理解为什么我的程序由于这个错误而崩溃 未捕获的类型错误 无法解析模块说明符 三 示例 jsm loaders GLTFLoader js 相对引用必须以 或 开头 我正在尝试使我的 html 文件与我创建的 serial js 文件进
  • 防止片段着色器中的循环展开

    我正在使用最新版本的 Chrome 和 Firefox 为 WebGL GLSL ES 1 0 编写一个片段着色器 并且编写了一个迭代算法 首先 我发现循环的长度是非常有限的 文档说它必须在编译时是可猜测的 这意味着它必须是一个常量或非常接
  • OpenGL 和 WebGL 的 Alpha 渲染差异

    I m rendering the same scene using the same exact C code once to native OpenGL on windows and once using Emscripten to W
  • Three.js 使用 WebRTC 并应用 Shader

    我不知道如何将着色器应用于具有视频纹理的 Three js 对象 我一直在使用 webRTC 和 Three js 并使用标准材质成功将视频纹理映射到网格上 var material new THREE MeshBasicMaterial
  • 着色器:如何在不生成几何体的情况下绘制 3D 点顶点?

    我有一个 3D Webgl 场景 我正在使用Reglhttp regl party http regl party 这就是WebGL 所以我本质上是直接写 GLSL 这是一个游戏项目 我有一个 3D 位置数组 x y z 它们是子弹或射弹
  • Three.js 的外观似乎被翻转了

    我这里有一个演示 测试场地 http www myuplay com game test html or Backup http direct myuplay com game test html 由于某种原因 即使鼠标矢量是正确的 我的对
  • 如何添加标签/标签以显示在多个对象的顶部,以便当用户单击对象时标签始终面向相机?

    本质上 我想说的是 我想创建一个出现在对象顶部 表面上的标签或标签 以便当用户单击对象时 即使对象旋转 标签也始终面向相机 我该如何去做呢 我被告知要使用正交相机 但我不确定如何 和 CSS 作为标签 请参阅上一篇文章 如何使我的文本标签始
  • WebGL 绘制图像

    我是 WebGL 新手 之前在 Java 中使用过 OpenGL 我一直在尝试编写一个简单的函数 该函数以特定的大小和旋转在特定位置绘制图像 但在网上搜索了一段时间后 我的代码仍然无法运行 目前 我已经成功绘制了图像 但是该图像距离正确的位
  • 如何从 dxf 文件解析 nurbs 曲面?或者你知道用于解析它的库(对于js,如果存在或任何其他语言)?

    我正在尝试解析 autocad nurbs 曲面并使用 JavaScript 中的 webGL 进行三角测量绘制 我已经在寻找 bjnortier 的 dxf 解析器 它支持大多数实体 如直线 圆弧 3Dface 折线 lwpolyline
  • 3D 图形矩阵 4x4 中最后一行的 magic 4 的用途是什么?

    当我阅读有关WebGL的书时 我看到了下一个矩阵描述 有关于书中最后一行的信息 WebGL 初学者指南 初学者指南 Diego Cantor Brandon Jones 神秘的第四排 第四排没有任何特殊之处 意义 元素 m4 m8 m12
  • 上传统一块的正确顺序是什么?

    在示例页面中https www lighthouse3d com tutorials glsl tutorial uniform b locks https www lighthouse3d com tutorials glsl tutor
  • 解决 Three.js / webGL 中的 gl_PointSize 限制

    我正在使用 Three js 创建交互式数据可视化 此可视化涉及渲染 68000 个节点 其中每个不同的节点具有不同的大小和颜色 最初我尝试通过渲染网格来实现此目的 但事实证明这非常昂贵 我当前的尝试是使用 Three js 粒子系统 每个
  • 如何清除WebGL中的矩形区域?

    WebGL 有一个clear清除整个表面的方法 清除表面的特定矩形的最佳方法是什么 例如 我想将一个从 50 50 开始的 100x100 像素框设置为全零 ARGB 0 0 0 0 我现在能想到的就是用一个写入零的片段着色器绘制一个四边形
  • WebGL 如何设置深度缓冲区中的值?

    在 OpenGL 中 深度缓冲区值是根据场景的近剪裁平面和远剪裁平面计算的 参考 从深度缓冲区获取真实的 z 值 https stackoverflow com questions 6652253 getting the true z va
  • 如何优化 Three.js 中多个 sphereGeometry 的渲染?

    我想优化 Three js 中 sphereGeometry 的渲染 因为它成为我的程序的瓶颈 javascript程序如下所示 var sphereThree for var idSphere 0 idSphere lt numSpher
  • 在 Chrome 18 中检测 SwiftShader WebGL 渲染器

    我有一个 2D HTML5 游戏引擎 www scirra com http www scirra com 并且确实想检测 WebGL 是否将使用 Chrome 18 的 Swiftshader 软件渲染器进行渲染 如果是这样我们会much
  • OpenGL ES 中的高效绘图方法

    在我的应用程序中 我通过 OpenGL ES Api 绘制了很多立方体 所有立方体的尺寸相同 只是它们位于空间坐标不同 我可以想到两种绘制它们的方法 但我不确定哪一种是最有效的 我不是OpenGL专家 所以我决定在这里问 方法1 这就是我现
  • Morph 目标为 Three.js

    我正在尝试开始使用变形目标和 Three js 然而 关于这个主题的文档似乎并不多 当我查看源代码时 morphTargetInfluences 似乎是有魔力 这是如何运作的 我该如何使用这个 值为1就是全力吗 如何区分同一模型上的不同变形
  • Three.js WebGL 从着色器绘制圆形自定义填充和边框颜色

    我将 Three js 与 WebGLRenderer 一起使用 我试图找出或查看如何使用 CircleGeometry 绘制圆圈的示例 并能够从顶点或片段着色器控制其填充和边框颜色 如果不使用图像作为纹理 这是否可能 抱歉 如果这真的很简
  • glClipPlane - webGL 中有等效的吗?

    我有一个 3D 网格 是否有可能像这样呈现剖面图 剪辑 glClipPlane在OpenGL中 我正在使用 Three js r65 我添加的最新着色器是 片段着色器 uniform float time uniform vec2 reso

随机推荐

  • Office 365 与桌面 Excel 宏

    抱歉 如果标题非常模糊 我已经尝试解决这个问题有一段时间了 但我不得不说 我对 Office 365 及其相关知识知之甚少 我在 Excel 2010 中开发了一系列宏 其中包括数据输入和子流程自动化 但最近我们被告知 我们将更明确地转向
  • 为什么打字稿允许我导入它在运行时无法使用的依赖项?

    您可以在这里查看我的示例项目 https github com DanKaplanSES typescript stub examples tree JavaScript import invalid https github com Da
  • 如何使用 PHP 进行单点登录? [关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 例如 使用单个 Google 帐户登录 Gmail Orkut Wava 和 feedburner 你的问题太不具体 无法给出准确的答
  • PHP 中检测整数?

    如何判断 PHP 中的浮点数是否为整数 is round 1 5 false is round 1 0 true is round 1 00000001 false 根据 sterofrog 的评论修改 Rob 的代码 代码检查以确保该值也
  • 如何使用 apache-commons net 中生成的证书配置客户端身份验证

    首先 我知道有一个类似的问题here https stackoverflow com questions 13471015 how to configure client authentication with apache commons
  • Bash 可以配置为在当前输入行上搜索字符串吗?

    用于在使用命令行时快速定位位置 是的 我是 Emacs 粉丝 看了Bash的man后 我找不到这样的提示 是否需要修改readline的源代码来支持这一点 非常感谢 我不知道有什么方法可以直接在命令行中执行此操作 但 bash 确实支持按键
  • 当 Javascript 更改值时,不检查 HTML 输入有效性

    我有一个文本输入minlength定义的 当用户输入文本时 输入的validity状态立即更新 如果我更改代码中的值 有效性状态将重置为显示为有效 即使违反了约束 validity valid是真的 const input document
  • 如何使用 selenium 和单个 NUnit 套件测试多个浏览器并保持干燥?

    我正在寻找一种方法来重用一个 NUnit 测试套件 而无需为每个浏览器复制整个套件 看来我需要为每个浏览器一个新的固定装置 我可以从 NUnit gui 发送某种环境变量或配置设置来切换浏览器吗 见下文 TestFixture public
  • 强制 Eclipse 忽略字符编码属性

    我正在使用一个 Web 框架 该框架在其 html 模板中使用动态字符编码 如下所示 问题是当我尝试在 Eclipse 中编辑这个文件时 Eclipse 认为这是一种文字编码类型 因此拒绝打开该文件 并说 不支持的字符编码 字符编码 此平台
  • 为什么 ELF header 与文本段一起加载到内存中?

    我编译了这个程序 m32 nostdlib进入 ELF 可执行文件 void start 当我这样做的时候readelf l我很惊讶地发现 LOAD 段上的偏移量是 0x000000 因为这意味着可执行标头将与文本段同时加载到内存中 于是我
  • 如何在 Angular 中获取 DOM 节点属性

    我在用这个答案 https stackoverflow com a 35385518 10684507将 HTML 字符串转换为 Angular 中的 DOM 元素 问题是我无法获取属性Node getAttribute 无法使用 因为打字
  • 根据出生日期计算年龄(jQuery 或 PHP)[不基于用户输入]

    我正在寻找一个 JavaScript 或 PHP 脚本 可以让我根据某人的出生日期来计算他 她的年龄mm dd yyyy格式 我发现这个非常有用的链接 在 JavaScript 中计算年龄 https stackoverflow com q
  • swagger codegen 正在覆盖生成文件中的自定义代码

    我使用 swagger codegen 生成 jaxrs 服务器端类和客户端 java 类 这是我用来生成类的命令 java jar modules swagger codegen distribution target swagger c
  • 如何使用 Google 托管的 jQuery UI 源?

    我需要加载 jQuery UI 文件 并且想从 Google 执行此操作 目前我上传 我需要从 Google 获取哪些相应文件 我可以用吗http ajax
  • 检测 NSDictionary 中的 Null 值

    我有一个NSDictionary它是由 API 服务器的 JSON 响应填充的 有时该字典中键的值是Null 我试图获取给定的值并将其放入表格单元格的详细文本中进行显示 问题是 当我尝试将值强制转换为NSString我发生了车祸 我thin
  • R中有没有办法告诉某个纬度/经度坐标属于哪个大陆?

    我正在使用maps在 R 中打包 并希望在每个大陆上制作一个文本标签 说明我正在绘制的点有多少个在每个大陆上 虽然我可以制作粗略的方框来勾勒出每个大陆的轮廓 但它们并不那么准确 例如 有时包括欧洲 非洲的部分地区等 R 中是否有一些功能可以
  • Java 中的异常翻译与异常链接

    有什么区别Exception Translation and Exception Chaining在Java中 根据约书亚 布洛赫 in 有效的Java 异常翻译较高层应捕获较低级别的异常 并在其位置抛出可以用以下方式解释的异常 更高层次的
  • 在使用curses的Python程序中,Setupterm找不到终端

    我正在尝试使用Python 使用PyCharm 2 0 运行一个简单的curses脚本 这是我的脚本 import curses stdscr curses initscr curses noecho curses cbreak stdsc
  • 自定义 matplotlib 图:带有彩色单元格的棋盘式表格

    当我学习 python 和这个有趣的绘图库时 我开始使用 matplotlib 渲染绘图 我需要帮助解决我正在解决的问题的自定义绘图 可能已经有一个内置函数可以实现此目的 问题 我正在尝试绘制一个表格 矩形 作为包含 96 个单独单元格 8
  • WebGL 如何避免长时间着色器编译导致选项卡停顿

    我有一个巨大的着色器 需要一分多钟的时间来编译 在这个过程中完全停止了整个浏览器 据我所知 着色器编译不能异步 因此您可以在等待编译完成时运行其他 WebGL 命令 我已经尝试过以下操作 在一段时间内不要使用该特定着色器 这不起作用 因为大