android — Какую поверхность использовать для eglMakeCurrent для контекста, который отображается только в FBO

У меня следующая ситуация:

В кроссплатформенной библиотеке рендеринга для iOS и Android (написанной на c (++)) у меня есть два потока, каждый из которых нуждается в своем собственном EGLContext:
Нить А является основной нитью; это делает окно.
Поток B является потоком генератора, который выполняет различные вычисления и отображает результаты в текстуры, которые впоследствии используются потоком A.

Поскольку я не могу использовать EGL на iOS, библиотека использует указатели на статические функции Obj.-C, чтобы создать новый контекст и установить его текущим.
Это уже работает, я создаю контекст для потока A, используя

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

Контекст для потока B создается с использованием

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

Затем я могу установить любой из двух текущих:

[EAGLContext setCurrentContext:context];

Чтобы использовать ту же логику (указатели функций передаются в библиотеку) на Android, я хочу сделать это на стороне C привязок JNI, на этот раз используя реальный EGL вместо EAGL от Apple.
Я могу легко создать contextA, используя WindowSurface и собственное Window, я могу создать contextB и передать contextA параметру shareContext вызова eglCreateContext.

Но когда я хочу сделать contextB текущим, я должен передать поверхность вызову eglMakeCurrent, и я пытаюсь выяснить, какую поверхность туда передать.

  • Я не могу использовать WindowSurface, который я использую для contextA как спекуляция в разделе 3.7 говорится, что «не более одного контекста для каждого поддерживаемого клиентского API может быть текущим для определенного потока в данный момент времени, и не более одного контекста может быть связано с конкретной поверхностью в данный момент времени».
  • Я не могу указать EGL_NO_SURFACE, потому что это приведет к ошибке EGL_BAD_MATCH в вызове eglMakeCurrent.
  • Кажется, я мог бы использовать поверхность PBuffer, но я сомневаюсь, потому что мне придется указывать ширину и высоту, когда я создаю такую ​​поверхность, а поток B может захотеть создавать текстуры разных размеров. В дополнение к этому, «Руководство по программированию OpenGL ES 2.0» Манши, Гинзбург и Шрайнер в разделе 3.8 заявляют, что «Pbuffers чаще всего используются для генерации текстурных карт. Если все, что вы хотите сделать, это рендерить текстуру, мы рекомендуем использовать объекты framebuffer […] вместо pbuffers, потому что они являются более эффективными «, что именно то, что я хочу сделать в потоке B.

Я не понимаю, что Мунши, Гинзург и Шрайнер подразумевают под этим предложением, как объект фреймбуфера мог бы заменить поверхность pbuffer? Что, если я создаю очень маленькую (скажем, 1x1px) поверхность pbuffer, чтобы сделать контекст текущим — могу ли я тогда рендерить в произвольно большие FBO? Есть ли другие возможности, о которых я еще не знаю?

Большое спасибо за вашу помощь!

6

Решение

Поверхность, которую вы передаете eglMakeCurrent (), должна быть поверхностью EGL из eglCreateWindowSurface (). Например:

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

Но, например, eglCreateWindowSurface () требует SurfaceTexture, который предоставляется обратному вызову onSurfaceTextureAvailable () при создании TextureView, но вы также можете создавать внеэкранные SurfaceTextures без какого-либо View.

Вот пример приложения, которое использует TextureView в Android SDK здесь, хотя оно использует SurfaceTexture для видео камеры, а не рендеринга OpenGL ES:

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

По умолчанию поверхность EGL для FBO будет иметь тот же размер, что и SurfaceTexture, из которой они были созданы. Вы можете изменить размер SurfaceTexture с помощью:

    surfaceTexture.setDefaultBufferSize(width, height);

Не используйте pbuffers на Android, потому что некоторые платформы (Nvidia Tegra) не поддерживают их.
Эта статья подробно объясняет преимущества FBO над pbuffers:

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

3

Другие решения

В итоге я использовал поверхность PBuffer (размером 1×1) — тогда я создал FBO и рендерил в текстуры просто отлично. Для их отображения (в другом потоке и другом (совместно используемом) контексте opengl) я использую интерфейс Windows с ANativeWindow (пример этого где-то в SDK).

2

Если рисование в FBO — единственное, что вы хотите сделать, вы можете получить любой EGLContext, который уже создан вами или кем-то еще (например, GLSurfaceView), и сделать его текущим, тогда вы просто создадите свое 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();
}

С ++ аналог

void setup_context() {
context = eglGetCurrentContext();
display = eglGetCurrentDisplay();
surface = eglGetCurrentSurface(EGL_DRAW);
}
0
По вопросам рекламы [email protected]