WebAssembly和OpenGL - 单一上下文,多个输出(到画布)

6

(OpenGL / Emscripten的新手)

我正在构建一个股票交易客户端应用程序,需要40多个开放式图表。其中约50%处于某种“自由绘制”状态,这意味着它们显示蜡烛图以及其他线条/箭头/图像等。

在过去几个月中尝试了很多选项后,最后得出以下结论。

  • HighCharts:易于使用但速度较慢;
  • CanvasJS:更快但不够快
  • WebAssembly + OpenGL:速度更快,但工作量更大(仍然值得投入)

我引导单个WebAssembly应用程序实例,并调用它上面的函数,让C ++使用OpenGL创建图表,该图表映射到WebGL(2)。一切正常运作。

我之所以选择(WebAssembly + OpenGL) -> Emscripten是因为有很多数字计算,而c ++也适合这项工作 :)

问题是WebGL在Chrome(59)中有大约10个上下文限制。因此,拥有40-100个WebGL上下文(图表)并不是一个明智的想法,我的直觉告诉我这是一种浪费OpenGL资源的方式,因为几乎总是将这么多上下文输出为静态图像,除非您滚动图表等。
有没有人在将单个OpenGL上下文呈现到随机画布元素(或任何其他元素,其实并不重要)方面有很好的经验?
我的想法如下:
1.使用另一个线程中的离屏画布开始c++ OpenGL, https://github.com/OleksandrChekhovskyi/emscripten-offscreen-canvas-test/blob/master/main.c#L35 2.Javascript告诉c++渲染图表
3.通过共享的Uint8Array与JS共享/渲染OpenGL后备缓冲区...SharedArrayBuffers由C++在JS Worker线程中填充,并且主(渲染)线程仅读取/转换以将图像写入画布/HTML元素。
我似乎找不到其他不创建许多OpenGL上下文的方法。
问题是:这样做的性能如何,基本上将OpenGL缓冲区复制到JavaScript等等?它是否偏离了轨道?
谢谢

enter image description here

p.s. 底部的图表(带红色波浪线)现在由WebAssembly和OpenGL(GLFW等)渲染

------ 更新 -----

选项2:始终将内容渲染到同一画布,并使用JS将画布上下文复制到另一个画布中(但如果上下文更新,它可能会被擦除..)


“需要40多个打开的图表”吗?如果您实际上并没有同时显示那么多图表,那么您实际上并不需要拥有那么多单独的上下文。您只需要拥有足够的上下文来显示当前需要的内容,而不是可能需要的内容。 - Nicol Bolas
它们基本上都是渲染和随机更新的,但不在单个容器内。可能会有一个带图表(或3个)的模态框,一个带图表和内部调试器的侧滑块等等。如果它是一个完全渲染的OpenGL应用程序,我会选择单个上下文,但是在HTML中混合使用时可能会更加困难。此外,我不想重新渲染所有图表,如果只有一个发生了变化。 - DutchKevv
1个回答

5

因此,在构建更多内容后,我找到了���个快速的解决方案。

我只使用了一个上下文(GLFW),并通过JS触发C ++函数来渲染图表,一旦完成,c ++使用相应的图表ID通过EM_ASM_向JS发送信号以将结果(图像)呈现到其目标画布宽度:

chart.el.getContext('2d').drawImage(Module.canvas, 0, 0, width, height, 0, 0, width, height);

我测试了它,它的速度非常快,从画布中复制图像始终少于1毫秒。即使在具有2K+图像的4K屏幕上也是如此。
而且,当Chrome完全支持离屏画布时,我可以将WebAssembly渲染部分加载到Web Worker中,并完全绕过主线程,甚至可以实时切换画布上下文以立即渲染到目标画布,让其变得更快。但这还不可能(还需要几个月:))
因此,除非浏览器支持100多个webGL上下文,否则我想这将是未来最快的解决方案。

非常有趣。为了澄清,您是在C++/GLFW中呈现图表,并将生成的图像发送回JavaScript,在那里它被贴到画布的一部分上吗?您能提供此代码的示例吗?仅创建上下文,没有任何财务应用程序的实质内容? - Jack
1
嗨,@Jackalope.. 有一段时间没有碰这个项目了。但是为了澄清一下:一个隐藏的画布元素作为唯一的GLFW上下文。每个DOM画布都创建一个具有唯一ID的C++类实例,每次可见画布需要重新渲染(例如通过点击等),通过WASM函数调用具有唯一画布ID和更改参数(w/h)的C++方法,在相应的c++类上调用绘制函数并让GLFW渲染到主上下文,c++向JS发出信号,表示渲染完成并带有唯一ID,JS将隐藏的画布转换为BPM图像,JS将图像注入到具有相应#id的画布中。所有操作同时进行 :) - DutchKevv
@DutchKevv,你能分享一下实现这个功能的相关代码吗? - ZivS
最快的解决方案是使用视口/剪切和一个屏幕大小的上下文。它避免了所有的复制。您可以在此处查看解决方案示例:https://stackoverflow.com/a/30546250/128511 - gman

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接