我正在使用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在不执行绘制调用的情况下上传此纹理?
答案 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。
不幸的是,除了通过texImage2D
和texSubImage2D
以外,无法将视频上传到WebGL
某些浏览器试图使这种情况更快地发生。我注意到您正在使用gl.LUMINANCE
。您可以尝试使用gl.RGB
或gl.RGBA
看看情况是否会加快。浏览器可能只会针对更常见的情况进行优化。另一方面,它们可能根本没有优化。
已经提出了两个扩展,它们允许不带副本使用视频,但是AFAIK没有浏览器实现了它们。
实际上,这是一个比听起来要难得多的问题。
视频数据可以采用多种格式。您提到了YUV,但还有其他人。浏览器应该告诉应用程序格式,还是应该将浏览器转换为标准格式?
告诉问题是,许多开发人员会弄错它,然后用户将提供他们不支持的格式的视频
WEBGL_video_texture
扩展名通过重写着色器而转换为标准格式。您告诉它uniform samplerVideoWEBGL video
,然后知道它可以将您的color = texture2D(video, uv)
重写为color = convertFromVideoFormatToRGB(texture(video, uv))
。这也意味着,如果您播放不同格式的视频,他们将不得不即时重写着色器。
同步
将视频数据传输到WebGL听起来很棒,但是现在您遇到的问题是,到获取数据并将其呈现到屏幕时,您已经添加了几帧延迟,因此音频不再同步
如何处理该问题超出了WebGL的范围,因为WebGL与音频没有任何关系,但确实指出,这不只是向WebGL提供数据那么简单。一旦您提供了数据,人们就会要求更多的API来获取音频和更多信息,以便他们可以延迟一个或两个并保持同步。
TLDR ;除了通过texImage2D
和texSubImage2D