如何最好地访问计算着色器中的 ARCore 视频帧

How best to access ARCore video frame in compute shader

我正在实施一项使用 ARCore(当前为 1.16.0)以及在 OpenGL ES 3.2 计算着色器中进行自定义图像处理的技术。

我可以通过两种方式从计算着色器访问视频帧,这两种方式都有缺点:

  1. 使用 Session.setCameraTextureName(). 这似乎是一个自然的选择,因为我让 ARCore 为我将数据导入 OpenGL 纹理。然而它是在 RGBA 中,这大概意味着在我获取数据之前发生了不需要的有损转换。此外,由于它是 GL_TEXTURE_EXTERNAL_OES 纹理,我无法直接访问像素(使用 imageLoad()),必须通过采样器。此外,在我测试过的设备上,每个 CameraConfig 的纹理分辨率都是 1080,这对我的计算算法来说太多了,需要缩小比例。
  2. 使用 Frame.acquireCameraImage(). 这里的优点是我在 YCbCr 中获得图像,大概跳过了有损转换步骤,并且我可以 select适当的决议。缺点是我需要进行两次 glTexSubImage2D() 调用。

(有趣的是,在三星 S8 和 A3 上,所有配置的纹理分辨率均为 1920x1080,图像分辨率为 640x480、1280x720 和 1920x1080。)

ARCore + 计算似乎有点灰色地带。欢迎任何关于哪个是更好的选择的建议,但请引用来源。 :)

编辑:根据反馈添加一些具体问题:

What path is generally used behind the scenes to go from YCbCr image in main memory to RGBA OpenGL ES texture?

使用GL_TEXTURE_EXTERNAL_OES基本上是零拷贝访问。 GPU可以直接访问camera/video块写入的YUV图像。颜色转换是即时进行的;这样做可能会有一些 GPU 开销 - 这将取决于硬件 - 但不会在内存中创建第二个 RGB 副本。多少开销 - 现代移动 GPU 可以非常有效地执行此操作,但较旧的 GPU 可能有 2 倍的两平面 YUV 纹理成本。

Is this path faster than glTexSubImage2D()?

一般来说,是的,这就是存在直接访问路径的原因。但是,您必须在一种情况下而不是另一种情况下注入额外的下采样这一事实并不能使这一点变得显而易见 "right answer"。

另请注意,费用不同。直接 YUV-RGB 转换会产生 GPU 成本。纹理上传会产生 CPU 费用。根据设备的相对 CPU/GPU 性能,以及应用程序的其余部分使用的资源,其中一个可能比另一个更轻松。

Am I paying the computational cost for this regardless of whether I'm setting the session's texture name?

没有。 YUV 到 RGB 的转换是在访问纹理时在采样器中完成的。

Does the main-memory YCbCr image always come before the RGBA texture in the conversion chain?

RGBA 纹理完全是虚拟的 - 它不存在于内存中。

the texture resolution for all configs is 1920x1080, and the image resolutions are 640x480, 1280x720 and 1920x1080.

请注意,相机 HAL 层中有很多特定于供应商的 "magic"。不可能说低分辨率图像是如何创建的;它们可以由相机直接以较低的分辨率生成,或者它们可以由供应商 HAL 在单独的通道中缩小(如果相机不能直接这样做,通常使用硬件缩放器)。