我能在两个OpenGL上下文间共享外部纹理吗?(Android相关)

9
我正在创建2个线程。每个线程都有自己的EGL上下文。 一个线程在本地,在其中我将渲染到纹理,另一个线程在Java中,在其中我想从该纹理中采样并将其呈现到屏幕/编码器(无论哪种方式)。 但我做不好。 我尝试在任何一个线程上生成纹理。我注意到的是纹理ID在两个线程上都是重复的(我有其他不应共享的纹理)。
我的问题是,是否可能在两个线程(和上下文)之间共享纹理?
编辑:解决方案
由于Andon和一些Google搜索的帮助,我能够让它工作。我在第一个线程上在Java中创建了一个上下文,然后调用eglGetCurrentContext()在C++中获取EGLContext。稍后,我在第二个线程中使用以下内容在C++中创建第二个上下文: eglCreateContext(mEglDisplay,mEglConfig,sharedContext,contextAttribs); 其中sharedContext是第一个上下文。

栅栏同步对象将是首选的同步方法,但我认为OpenGL ES中没有这些?(顺便说一下,您的问题标记错误 - 应该是OpenGL ES) - Andon M. Coleman
你在标题中提到了“外部纹理”,但在问题中并没有提到,而且听起来你只是使用普通的OpenGL纹理。你能澄清一下到底是哪一个吗? - Reto Koradi
是的,我正在使用外部纹理。 - Michael P
使用外部纹理,您应该能够在不同的共享组上下文之间共享图像数据。它们甚至可以在进程之间工作。当然,每个共享组中都需要一个纹理对象,但是这些纹理可以由相同的图像支持。但是,只要一切都在同一个进程中,就没有必要费心处理外部纹理。将上下文放入同一个共享组并使用常规纹理可能会更简单。 - Reto Koradi
1
在Grafika(https://github.com/google/grafika)中的“show + capture camera”活动可以实现这一功能,它通过在不同线程中的两个EGL上下文之间共享从相机接收到的外部纹理来实现(一个用于在屏幕上绘制,一个用于提供给MediaCodec编码器)。但由于显示上下文由GLSurfaceView管理,所以有点棘手,因为它并不太喜欢共享。 - fadden
显示剩余2条评论
1个回答

3

是的,不同上下文之间可以共享资源。

然而,在共享的上下文中,命令流并不是同步的;如果你在一个线程中上传数据并在另一个线程中使用它,你必须格外小心,确保上传操作已经完成 (glFinish (...) 然后再使用一些自己的同步构造,如信号量)。

现在,关键问题是——你是否能控制这些上下文的创建?这是在 EGL 中进行资源共享所必需的。你只需要自己创建一个上下文;如果你已经拥有了另一个上下文,你可以将其用作创建第二个上下文时的共享上下文。


我对两个上下文都有完全的控制权,因为我正在创建它们。glFinish是做什么用的?正如我所提到的,它没有起作用。在一个线程上渲染纹理可以正常工作,但是当我从另一个上下文的另一个线程中使用该纹理ID进行采样时,屏幕会变成空白。 - Michael P
@MichaelP:glFinish(...)会阻塞,直到所有前面的命令都执行完毕。否则,GL有将命令放入队列并在GPU空闲时执行它们的倾向。这通常很好,但在多线程渲染时非常糟糕。您需要在一个线程中生成纹理的操作之后立即调用glFinish(...),一旦该命令返回,您可以向渲染线程发出信号,表示有有效的纹理数据等待绘制。否则,两个线程将异步运行,这是一团糟。 - Andon M. Coleman
1
@MichaelP:通常在单线程/单上下文渲染场景中,您不必考虑这些内容,GL会自动执行此类同步。但是,当您使用两个单独的上下文时,它们会并行执行命令,您需要确保命令执行的顺序是一致的。但是,如果您没有通过将其传递给eglCreateContext(...)来建立其中一个上下文作为共享上下文,则所有这些都将无法正常工作。 - Andon M. Coleman
成功了!谢谢 @Andon 我会在问题中更新解决方案。 - Michael P

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接