У меня следующая ситуация:
В кроссплатформенной библиотеке рендеринга для 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, и я пытаюсь выяснить, какую поверхность туда передать.
Я не понимаю, что Мунши, Гинзург и Шрайнер подразумевают под этим предложением, как объект фреймбуфера мог бы заменить поверхность pbuffer? Что, если я создаю очень маленькую (скажем, 1x1px) поверхность pbuffer, чтобы сделать контекст текущим — могу ли я тогда рендерить в произвольно большие FBO? Есть ли другие возможности, о которых я еще не знаю?
Большое спасибо за вашу помощь!
Поверхность, которую вы передаете 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
В итоге я использовал поверхность PBuffer (размером 1×1) — тогда я создал FBO и рендерил в текстуры просто отлично. Для их отображения (в другом потоке и другом (совместно используемом) контексте opengl) я использую интерфейс Windows с ANativeWindow (пример этого где-то в SDK).
Если рисование в 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);
}