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

时间:2019-05-23 21:22:55

标签: webgl

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

视频必须以30 fps的速度播放。为了做到这一点,我每隔一个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”纹理上载功能,则探查器将显示预期结果。每帧都有近一半的GPU时间。

据此,我猜测Y纹理不是使用texImage2d函数真正上传到gpu的。

但是,我真的不希望在屏幕上绘制Y纹理,因为它没有正确的UV纹理才能进行任何处理,直到一帧之后。那么有什么方法可以强制GPU在不执行绘制调用的情况下上传此纹理?

1 个答案:

答案 0 :(得分:1)

更新

我误解了这个问题

这实际上取决于驱动程序。问题是OpenGL / OpenGL ES / WebGL的纹理API确实很糟糕。吸吮是“有意料之外的后果”的技术术语。

问题在于,驱动程序在绘制之前无法真正完全上传数据,因为它不知道要更改什么。您可以按任意顺序和大小更改所有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之前,替换级别3应该怎么做?然后,您添加了4 8x8、5作为4x4、6作为2x2和7作为1x1的级别。

如您所见,API使您可以按任何顺序更改mips。实际上,我可以将7级分配为723x234,然后在以后进行修复。该API的设计宗旨是直到绘制时所有mips的大小都必须正确,然后才能最终在GPU上分配内存并复制mips。

您可以看到此问题here的演示和测试。该测试将杂乱无章的上载杂乱无章地上传,以验证WebGL实施是否因其大小都不正确而正确失败,并在它们正确大小后正确开始工作。

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

他们添加了gl.texStorage2D来进行修复,但gl.texStorage2D在仅WebGL1中不可用。 gl.texStorage2D虽然有新问题:(

TLDR ;调用gl.texImage2D时纹理会上传到驱动程序,但是驱动程序要到绘制时间才能上传到GPU。

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

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

旧答案

不幸的是,除了通过texImage2DtexSubImage2D以外,无法将视频上传到WebGL

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

已经提出了两个扩展,它们允许不带副本使用视频,但是AFAIK没有浏览器实现了它们。

WEBGL_video_texture

WEBGL_texture_source_iframe

实际上,这是一个比听起来要难得多的问题。

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

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

    WEBGL_video_texture扩展名通过重写着色器而转换为标准格式。您告诉它uniform samplerVideoWEBGL video,然后知道它可以将您的color = texture2D(video, uv)重写为color = convertFromVideoFormatToRGB(texture(video, uv))。这也意味着,如果您播放不同格式的视频,他们将不得不即时重写着色器。

  • 同步

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

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

TLDR ;除了通过texImage2DtexSubImage2D

,无法将视频上传到WebGL。