Webgl将纹理数据上传到gpu,无需绘制调用

Webgl将纹理数据上传到gpu,无需绘制调用,webgl,Webgl,我正在使用webgl在自定义视频编解码器上进行YUV到RGB的转换 视频必须以每秒30帧的速度播放。为了实现这一点,我每隔一个requestAnimationFrame就做一次数学运算 这非常有效,但我注意到在分析时,将纹理上传到gpu需要最长的时间 所以我分别上传了“Y”纹理和“UV”纹理 现在,第一个“requestAnimationFrame”将上传“Y”纹理,如下所示: gl.activeTexture(gl.TEXTURE0); gl.bindTexture(gl.TEXTURE_2D

我正在使用webgl在自定义视频编解码器上进行YUV到RGB的转换

视频必须以每秒30帧的速度播放。为了实现这一点,我每隔一个requestAnimationFrame就做一次数学运算

这非常有效,但我注意到在分析时,将纹理上传到gpu需要最长的时间

所以我分别上传了“Y”纹理和“UV”纹理

现在,第一个“requestAnimationFrame”将上传“Y”纹理,如下所示:

gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, yTextureRef);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.LUMINANCE, textureWidth, textureHeight, 0, gl.LUMINANCE, gl.UNSIGNED_BYTE, yData);
第二个“requestAnimationFrame”将以相同的方式上载“UV”纹理,并对片段着色器进行绘制调用,在它们之间进行数学运算

但这不会改变分析器中的任何内容。我仍然在上传“Y”纹理的帧上显示了接近0 gpu的时间,在上传“UV”纹理的帧上显示的时间与之前相同

但是,如果我向“Y”纹理上载函数添加draw调用,则探查器将显示预期结果。每一帧都有将近一半的gpu时间

从这一点上,我猜Y纹理并没有真正使用texImage2d函数上传到gpu

然而,我并不真的想在屏幕上绘制Y纹理,因为直到一帧之后,它才具有正确的UV纹理。那么,有没有办法强制gpu在不执行绘制调用的情况下上载此纹理?

Update 我误解了这个问题

这完全取决于司机。问题是OpenGL/OpenGL ES/WebGL的纹理API真的很糟糕。Sucks是一个技术术语,表示“有意外的后果”

问题是驱动程序在你画图之前不能完全上传数据,因为它不知道你要改变什么。您可以按任何顺序和大小更改所有mip级别,然后将它们全部固定在中间,直到绘制为止,它不知道您将调用哪些其他函数来操纵纹理

假设您创建了4x4 0级mip

gl.texImage2D(
   gl.TEXTURE_2D,
   0,        // mip level
   gl.RGBA,
   4,        // width
   4,        // height
   ...);
它应该分配什么内存?4(宽)*4(高)*4(rgba)?但是如果调用
gl.generateMipmap
,会怎么样?现在它需要4*4*4+2*2*4+1*1*4。好的,但现在您在级别3上分配了一个8x8 mip。然后,您打算分别用64x64、32x32、16x16替换级别0到2,但您首先执行了级别3。在更换高于这些级别的级别之前,当您更换级别3时,它应该做什么?然后添加级别4 8x8,5为4x4,6为2x2,7为1x1

正如您所见,API允许您以任何顺序更改mips。事实上,我可以将级别7分配为723x234,然后稍后修复它。API的设计目的是,直到绘图时,所有MIP都必须具有正确的大小,此时它们才可以最终在GPU上分配内存并在中复制MIP

您可以看到此问题的演示和测试。测试会无序上传mips,以验证WebGL实现是否正确失败,因为它们的大小不都正确,并且一旦大小正确,就可以正确开始工作

您可以看到,这可以说是一个糟糕的API设计

他们添加了
gl.texStorage2D
来修复它,但是
gl.texStorage2D
仅在WebGL1和WebGL2中不可用
gl.texStorage2D
有一些新问题:(

TLDR;调用
gl.texImage2D
时,纹理会上载到驱动程序,但驱动程序在绘制之前无法上载到GPU

可能的解决方案:使用
gl.texSubImage2D
,因为它不分配内存,所以驱动程序可能会更快上载。我怀疑大多数驱动程序不会这样做,因为您可以在绘图之前使用
gl.texSubImage2D
。仍然值得一试

我还要补充一点,
gl.LUMIANCE
可能也是一个瓶颈。IIRC DirectX没有相应的格式,OpenGL Core Profile也没有。两者都支持纯红色格式,但WebGL1不支持。因此,必须通过在上传时扩展数据来模拟LUMIANCE

旧答案 不幸的是,除了通过
texImage2D
texSubImage2D

一些浏览器试图加快这一速度。我注意到您使用的是
gl.LUMINANCE
。您可以尝试使用
gl.RGB
gl.RGBA
,看看速度是否加快。可能浏览器只针对更常见的情况进行优化。另一方面,它们可能根本没有进行优化

有人提出了两个允许在没有拷贝的情况下使用视频的扩展,但AFAIK浏览器从未实现过

这实际上是一个比听起来更难的问题

  • 视频数据可以有多种格式。您提到YUV,但还有其他格式。浏览器应该告诉应用程序该格式,还是应该将其转换为标准格式

    告诉的问题是很多开发者会弄错,然后用户会提供他们不支持的格式的视频

    WEBGL\u video\u texture
    扩展通过重新写入着色器转换为标准格式。您告诉它
    uniform sampler videowebgl video
    ,然后它知道它可以将
    color=texture2D(video,uv)
    重新写入
    color=convertfromvideoformatorgb(纹理(video,uv))
    。这还意味着,如果播放不同格式的视频,他们必须在运行中重新编写着色器

  • 同步

    将视频数据传输到WebGL听起来不错,但现在的问题是,在获取数据并将其渲染到屏幕时,您已经添加了几帧延迟,因此音频不再同步

    如何处理这一问题超出了WebGL的范围,因为WebGL与音频没有任何关系,但它确实指出,这并不是简单地向WebGL提供数据。一旦数据可用,人们就会要求更多的API来获取音频和更多信息,这样他们就可以延迟其中一个或两个,并保持同步