将 Uint8Array 渲染为 Canvas 的最快方法
Quickest way to render a Uint8Array to a Canvas
我收到了 Uint8Array
的 RGBA 值,以及图像的哪一部分已更新的一些信息。将此原始位图信息渲染回 canvas 的最快方法是什么?我一直在使用 2D 渲染上下文手动循环遍历数组并设置像素信息,但这非常慢:
let imageData = new ImageData(1920, 1080);
for (var i=0;i < args.frameBuffer.length; i+=4) {
imageData.data[i] = args.frameBuffer[i];
imageData.data[i+1] = args.frameBuffer[i+1];
imageData.data[i+2] = args.frameBuffer[i+2];
imageData.data[i+3] = args.frameBuffer[i+3];
}
context.putImageData(imageData, 0, 0, args.dirtyX, args.dirtyY, args.dirtyWidth, args.dirtyHeight);
执行此操作的更有效方法是什么? WebGL 会比 2D 上下文更高效吗?本机或通过类似 Three.js?
您可以使用 gl.TexSubImage2D 更新纹理,然后将整个纹理 blit。但 TexSubImage2D 存在性能问题,因为它必须等待之前的渲染完成才能为下一帧更新纹理。
更好的方法可能是对 webgl 使用 preserveDrawingBuffer 位,然后使用 TexImage2D 以循环方式使用两个纹理。要仅渲染脏区,您需要根据脏坐标为 DrawArrays 设置顶点数据。
WebGL 仍然需要大量复制数据,但也许这些复制路径比 putImageData 优化得更好。但是 webgl 可能会变慢是一个严重的危险,因为驱动程序经常针对纹理图像是静态的并用于多个渲染的用例进行优化。这使得渲染速度更快但上传纹理数据更慢。
为了解决昂贵的纹理上传问题,OpenGL 有多个扩展支持快速图像上传但渲染速度稍慢。可惜这些扩展对 webgl 不实用。
但是你的复制循环看起来很像你每次都在接收整个帧缓冲区,即使它只是部分更新。
如果你能做类似的事情
let imageData = new ImageData(args.frameBuffer, args.dirtyWidth, args.dirtyHeight);
context.putImageData(imageData, args.dirtyX, args.dirtyY);
当然你当前的界面可以用
重复
let imageData = new ImageData(args.frameBuffer, 1920, Math.floor((args.frameBuffer.length + 4*1919)/(4*1920)));
context.putImageData(imageData, 0,0, args.dirtyX, args.dirtyY, args.dirtyWidth, args.dirtyHeight);
我收到了 Uint8Array
的 RGBA 值,以及图像的哪一部分已更新的一些信息。将此原始位图信息渲染回 canvas 的最快方法是什么?我一直在使用 2D 渲染上下文手动循环遍历数组并设置像素信息,但这非常慢:
let imageData = new ImageData(1920, 1080);
for (var i=0;i < args.frameBuffer.length; i+=4) {
imageData.data[i] = args.frameBuffer[i];
imageData.data[i+1] = args.frameBuffer[i+1];
imageData.data[i+2] = args.frameBuffer[i+2];
imageData.data[i+3] = args.frameBuffer[i+3];
}
context.putImageData(imageData, 0, 0, args.dirtyX, args.dirtyY, args.dirtyWidth, args.dirtyHeight);
执行此操作的更有效方法是什么? WebGL 会比 2D 上下文更高效吗?本机或通过类似 Three.js?
您可以使用 gl.TexSubImage2D 更新纹理,然后将整个纹理 blit。但 TexSubImage2D 存在性能问题,因为它必须等待之前的渲染完成才能为下一帧更新纹理。
更好的方法可能是对 webgl 使用 preserveDrawingBuffer 位,然后使用 TexImage2D 以循环方式使用两个纹理。要仅渲染脏区,您需要根据脏坐标为 DrawArrays 设置顶点数据。
WebGL 仍然需要大量复制数据,但也许这些复制路径比 putImageData 优化得更好。但是 webgl 可能会变慢是一个严重的危险,因为驱动程序经常针对纹理图像是静态的并用于多个渲染的用例进行优化。这使得渲染速度更快但上传纹理数据更慢。
为了解决昂贵的纹理上传问题,OpenGL 有多个扩展支持快速图像上传但渲染速度稍慢。可惜这些扩展对 webgl 不实用。
但是你的复制循环看起来很像你每次都在接收整个帧缓冲区,即使它只是部分更新。
如果你能做类似的事情
let imageData = new ImageData(args.frameBuffer, args.dirtyWidth, args.dirtyHeight);
context.putImageData(imageData, args.dirtyX, args.dirtyY);
当然你当前的界面可以用
重复let imageData = new ImageData(args.frameBuffer, 1920, Math.floor((args.frameBuffer.length + 4*1919)/(4*1920)));
context.putImageData(imageData, 0,0, args.dirtyX, args.dirtyY, args.dirtyWidth, args.dirtyHeight);