6

I'm having the following situation:

In a cross platform rendering library for iOS and Android (written in c(++)), i have two threads that each need their own EGLContext: Thread A is the main thread; it renders to the Window. Thread B is a generator thread, that does various calculations and renders the results into textures that are later used by thread A.

Since i can't use EGL on iOS, the library uses function pointers to static Obj.-C functions to create a new context and set it current. This already works, i create the context for thread A using

EAGLContext *contextA = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];

The context for thread B is created using

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

I can then set either of the two current:

[EAGLContext setCurrentContext:context];

To use the same logic (function pointers passed to the library) on Android, i want to do this in the C side of the JNI bindings, this time using real EGL instead of Apple's EAGL. I can easily create contextA using a WindowSurface and the native Window, i can create contextB and pass contextA to the shareContext parameter of the eglCreateContext call.

But when i want to make contextB current, i have to pass a surface to the eglMakeCurrent call, and i'm trying to figure out what kind of surface to pass there.

  • I cannot use the WindowSurface i use for contextA as the spec says in section 3.7 that "At most one context for each supported client API may be current to a particular thread at a given time, and at most one context may be bound to a particular surface at a given time."
  • I cannot specify EGL_NO_SURFACE, because that would result in an EGL_BAD_MATCH error in the eglMakeCurrent call.
  • It seems I could use a PBuffer surface, but I hesitate because I'd have to specify the width and height when I create such a surface, and thread B might want to create textures of different sizes. In addition to that, the "OpenGL ES 2.0 Programming Guide" by Munshi, Ginsburg, and Shreiner states in section 3.8 that "Pbuffers are most often used for generating texture maps. If all you want to do is render to a texture, we recommend using framebuffer objects [...] instead of pbuffers because they are more efficient", which is exactly what i want to do in thread B.

I don't understand what Munshi, Ginsurg and Shreiner mean by that sentence, how would a framebuffer object be a replacement for a pbuffer surface? What if I create a very small (say 1x1px) pbuffer surface to make the context current - can i then still render into arbitrarily large FBOs? Are there any other possibilities I'm not yet aware of?

Thanks a lot for your help!

4

3 回答 3

3

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

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

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

这里有一个在 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

于 2013-06-11T00:19:04.030 回答
3

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

于 2014-03-16T18:38:18.407 回答
0

如果绘制到 FBO 是您唯一想做的事情,您可以获取您或其他人(例如 GLSurfaceView)已经创建的任何 EGLContext 并将其设为当前,然后您只需生成您的 FBO,然后使用它进行绘制。问题是如何将 GLSurfaceView 创建的上下文共享到您的跨平台 c++ 库。我通过在 c++ 中调用静态函数来获取 eglcontext 并在 Java 层将上下文变为当前状态后立即显示出来。像下面的代码:

//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);
}
于 2017-10-26T08:30:54.647 回答