解决 WebGL readPixels 变慢的问题
Working around WebGL readPixels being slow
我正在尝试使用 WebGL 来加速模拟小型量子电路的计算,例如 Quantum Computing Playground does。我 运行 遇到的问题是 readPixels
需要大约 10 毫秒,但我想在动画制作时每帧多次调用它,以便从 gpu 领域获取信息并进入 javascript-土地。
例如,这是我的确切用例。以下电路动画是通过计算每列门之间的状态创建的,以显示在线在线概率图:
按照我现在计算这些东西的方式,我需要为上述电路调用 readPixels 八次(在每列门之后调用一次)。这 waaaaay 目前太慢了,当我分析它时很容易花费 50 毫秒 (bleh)。
在这种用例中有哪些加速 readPixels 的技巧?
- 是否有显着影响 readPixels 速度的配置选项? (例如像素格式、大小、没有深度缓冲区)
- 在完成所有渲染调用之后,我是否应该尝试让
readPixel
调用同时发生(也许允许一些流水线操作)?
- 我是否应该尝试将我正在读取的所有纹理聚合到单个巨型纹理中,并在一次大读取后将其分类?
- 我应该使用不同的方法从纹理中获取信息吗?
- 我是否应该完全避免获取信息,并在 gpu 端进行所有布局和渲染(呃...)?
Should I try to make the readPixel calls all happen at once, after all the render calls have been made (maybe allows some pipelining)?
是的,是的,是的。 readPixels 从根本上说是一个阻塞的、管道停滞的操作,它总是会在它发生的任何地方破坏你的性能,因为它正在向 GPU 发送数据请求并且然后等待它响应,正常的绘制调用不需要这样做。
尽可能少地执行 readPixels(使用单个组合缓冲区进行读取)。尽可能晚做。其他一切都无关紧要。
Should I be avoiding getting the information out at all, and doing all the layout and rendering gpu-side (urgh...)?
这将使您的性能显着提高。
如果你的图形都像上面显示的那样,你根本不需要做任何“布局”(这很好,因为实现起来会很尴尬)——除了文字之外的一切都是一些一种可以在着色器中轻松完成的颜色或边界动画,并且所有布局都可以只是一个静态顶点缓冲区(每个顶点都有属性,它应该依赖于哪个模拟状态纹素)。
文本会更乏味,因为您需要将所有数字加载到纹理中以用作精灵表并对其进行查找,但这是一种标准技术。 (哦,还有 divide/modulo 来获取数字。)
我对你的用例了解不够,只是猜测,你为什么需要 readPixels?
首先,您不需要在 WebGL 中绘制文本或图表的静态部分。在 WebGL canvas 上放置另一个 canvas 或 svg 或 img,设置 css 以便它们重叠。让浏览器合成它们。那你就不用做了。
其次,假设您有一个纹理,其中包含您的计算结果。难道你就不能制作一些与图表中需要颜色的位置相匹配的几何体,并使用纹理坐标从结果纹理中的正确位置查找结果吗?那么你根本不需要调用 readPixels 。该着色器可以使用渐变纹理查找或任何其他技术将结果转换为其他颜色以对图表的动画部分进行着色。
如果你想根据结果绘制数字,你可以使用 a technique like this 这样你就可以在引用结果着色器时创建一个着色器来查看结果值,然后根据另一个纹理索引字形那。
我说的有道理吗?
我正在尝试使用 WebGL 来加速模拟小型量子电路的计算,例如 Quantum Computing Playground does。我 运行 遇到的问题是 readPixels
需要大约 10 毫秒,但我想在动画制作时每帧多次调用它,以便从 gpu 领域获取信息并进入 javascript-土地。
例如,这是我的确切用例。以下电路动画是通过计算每列门之间的状态创建的,以显示在线在线概率图:
按照我现在计算这些东西的方式,我需要为上述电路调用 readPixels 八次(在每列门之后调用一次)。这 waaaaay 目前太慢了,当我分析它时很容易花费 50 毫秒 (bleh)。
在这种用例中有哪些加速 readPixels 的技巧?
- 是否有显着影响 readPixels 速度的配置选项? (例如像素格式、大小、没有深度缓冲区)
- 在完成所有渲染调用之后,我是否应该尝试让
readPixel
调用同时发生(也许允许一些流水线操作)? - 我是否应该尝试将我正在读取的所有纹理聚合到单个巨型纹理中,并在一次大读取后将其分类?
- 我应该使用不同的方法从纹理中获取信息吗?
- 我是否应该完全避免获取信息,并在 gpu 端进行所有布局和渲染(呃...)?
Should I try to make the readPixel calls all happen at once, after all the render calls have been made (maybe allows some pipelining)?
是的,是的,是的。 readPixels 从根本上说是一个阻塞的、管道停滞的操作,它总是会在它发生的任何地方破坏你的性能,因为它正在向 GPU 发送数据请求并且然后等待它响应,正常的绘制调用不需要这样做。
尽可能少地执行 readPixels(使用单个组合缓冲区进行读取)。尽可能晚做。其他一切都无关紧要。
Should I be avoiding getting the information out at all, and doing all the layout and rendering gpu-side (urgh...)?
这将使您的性能显着提高。
如果你的图形都像上面显示的那样,你根本不需要做任何“布局”(这很好,因为实现起来会很尴尬)——除了文字之外的一切都是一些一种可以在着色器中轻松完成的颜色或边界动画,并且所有布局都可以只是一个静态顶点缓冲区(每个顶点都有属性,它应该依赖于哪个模拟状态纹素)。
文本会更乏味,因为您需要将所有数字加载到纹理中以用作精灵表并对其进行查找,但这是一种标准技术。 (哦,还有 divide/modulo 来获取数字。)
我对你的用例了解不够,只是猜测,你为什么需要 readPixels?
首先,您不需要在 WebGL 中绘制文本或图表的静态部分。在 WebGL canvas 上放置另一个 canvas 或 svg 或 img,设置 css 以便它们重叠。让浏览器合成它们。那你就不用做了。
其次,假设您有一个纹理,其中包含您的计算结果。难道你就不能制作一些与图表中需要颜色的位置相匹配的几何体,并使用纹理坐标从结果纹理中的正确位置查找结果吗?那么你根本不需要调用 readPixels 。该着色器可以使用渐变纹理查找或任何其他技术将结果转换为其他颜色以对图表的动画部分进行着色。
如果你想根据结果绘制数字,你可以使用 a technique like this 这样你就可以在引用结果着色器时创建一个着色器来查看结果值,然后根据另一个纹理索引字形那。
我说的有道理吗?