对于仅渲染到FBO的上下文,eglMakeCurrent使用什么Surface

时间:2013-06-09 12:51:54

标签: android c++ ios opengl-es-2.0 egl

我遇到以下情况:

在iOS和Android的跨平台渲染库中(用c(++)编写),我有两个线程,每个线程都需要自己的EGLContext: 线程A是主线程;它渲染到窗口。 线程B是一个生成器线程,它执行各种计算并将结果呈现为稍后由线程A使用的纹理。

由于我无法在iOS上使用EGL,因此库使用静态Obj.-C函数的函数指针来创建新的上下文并将其设置为当前。 这已经有效了,我使用

为线程A创建了上下文
EAGLContext *contextA = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];

线程B的上下文是使用

创建的
EAGLContext *contextB = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2 sharegroup:[contextA sharegroup]];

然后我可以设置两个电流中的任何一个:

[EAGLContext setCurrentContext:context];

要在Android上使用相同的逻辑(传递给库的函数指针),我想在JNI绑定的C端执行此操作,这次使用真正的EGL而不是Apple的EAGL。 我可以使用WindowSurface和本机Window轻松创建contextA,我可以创建contextB并将contextA传递给eglCreateContext调用的shareContext参数。

但是当我想让contextB变为当前时,我必须将一个表面传递给eglMakeCurrent调用,并且我试图弄清楚要在那里传递什么样的表面。

  • 我无法使用我用于contextA的WindowSurface,因为spec在第3.7节中说“每个支持的客户端API的最多一个上下文可能在给定时间对特定线程是最新的,并且最多一个上下文可能会在给定时间绑定到特定表面。“
  • 我无法指定EGL_NO_SURFACE,因为这会导致eglMakeCurrent调用中出现EGL_BAD_MATCH错误。
  • 我似乎可以使用PBuffer表面,但我犹豫不决,因为我必须在创建这样的表面时指定宽度和高度,而线程B可能想要创建不同大小的纹理。除此之外,Munshi,Ginsburg和Shreiner的"OpenGL ES 2.0 Programming Guide"在3.8节中指出“Pbuffers最常用于生成纹理贴图。如果你想做的就是渲染纹理,我们建议使用framebuffer对象[...]而不是pbuffers,因为它们更有效“,这正是我想在线程B中做的。

我不明白Munshi,Ginsurg和Shreiner的意思是什么,帧缓冲对象如何替代pbuffer表面?如果我创建一个非常小的(例如1x1px)pbuffer表面以使上下文变为当前状态,那么我仍可以渲染成任意大的FBO吗?还有其他我不知道的可能性吗?

非常感谢你的帮助!

3 个答案:

答案 0 :(得分:3)

传递给eglMakeCurrent()的表面必须是eglCreateWindowSurface()的EGL表面。例如:

    EGLSurface EglSurface = mEgl.eglCreateWindowSurface(mEglDisplay, maEGLconfigs[0], surfaceTexture, null);
    mEgl.eglMakeCurrent(mEglDisplay, EglSurface, EglSurface, mEglContext);

但是,eglCreateWindowSurface()需要一个SurfaceTexture,它在创建TextureView时提供给onSurfaceTextureAvailable()回调,但你也可以在没有任何View的情况下创建离屏SurfaceTextures。

有一个示例应用程序在Android SDK中使用TextureView,虽然它使用SurfaceTexture进行摄像机视频而不是OpenGL ES渲染:

sources\android-17\com\android\test\hwui\GLTextureViewActivity.java

默认情况下,FBO的EGL表面将与创建它们的SurfaceTexture具有相同的大小。您可以使用以下命令更改SurfaceTexture的大小:

    surfaceTexture.setDefaultBufferSize(width, height);

不要在Android上使用pbuffers,因为某些平台(Nvidia Tegra)不支持它们。 本文详细解释了FBO优于pbuffers的优点:

http://processors.wiki.ti.com/index.php/Render_to_Texture_with_OpenGL_ES

答案 1 :(得分:3)

我最终使用了PBuffer表面(大小为1x1) - 然后我创建了一个FBO并渲染到纹理中就好了。为了显示它们(在不同的线程和不同的(共享的)opengl上下文中),我使用带有ANativeWindow的windowsurface(在sdk的某处有一个样本)。

答案 2 :(得分:0)

如果只想绘制到FBO,你可以抓住已经由你或其他人创建的任何EGLContext(例如GLSurfaceView)并使其成为当前的,然后你只需生成你的FBO然后用它绘制。 问题是如何将GLSurfaceView创建的上下文分享到您的跨平台c ++库。我通过调用c ++中的静态函数来实现这一点,以便在上下文由Java层创建当前上下文后立即获取eglcontext和surface。比如下面的代码:

//This is a GLSurfaceView renderer method
@override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
    //up to this point, we know the EGLContext 
    //has already been set current on this thread.
    //call JNI function to setup context
    graphics_library_setup_context();
}

c ++对应

void setup_context() {
    context = eglGetCurrentContext();
    display = eglGetCurrentDisplay();
    surface = eglGetCurrentSurface(EGL_DRAW);
}