Threading textures загрузить процесс для android opengl

8 Victor [2011-06-11 23:15:00]

У меня есть большое количество текстур в формате JPG. И мне нужно предварительно загрузить их в память opengl до начала фактического рисования. Я задал вопрос, и мне сказали, что способ сделать это - отделить распаковку JPEG от вызовов glTexImage2D (...) в другой поток. Проблема в том, что я не совсем уверен, как это сделать.

OpenGL (обработчик?), необходимый для выполнения glTexImage2D, доступен только в методах GLSurfaceView.Renderer onSurfaceCreated и OnDrawFrame.

Я не могу распаковать все свои текстуры, а затем в onSurfaceCreated (...) загрузить их в opnegl, потому что они, вероятно, не будут вписываться в ограниченную память vm (20-40MB?)

Это означает, что я должен распаковывать и загружать их по очереди, но в этом случае я не могу получить указатель opengl.

Может ли кто-нибудь, пожалуйста, дать мне и пример загрузки потоков текстур для игры opengl?

Это должна быть какая-то типичная процедура, и я нигде не могу получить информацию.

android opengl-es textures


5 ответов


2 Решение Christian Rau [2011-06-12 03:43:00]

У вас есть свой основной поток с программой загрузки, которая имеет доступ к OpenGL и вызывает glTexImage2D. Другой поток загружает (и декодирует) изображение из файла в память. В то время как вторичный поток загружает следующее изображение, основной поток загружает ранее загруженное изображение в текстуру. Таким образом, вам нужна только память для двух изображений, одна из которых загружена из файла, а другая из них загружена в GL (которая была загружена ранее). Конечно, вам нужна небольшая синхронизация, чтобы предотвратить перезагрузку потоком загрузчика, что основной поток в настоящее время отправляет GL и предотвращает отправку основного потока недоделанных данных.


10 Rodja [2013-11-02 13:23:00]

Как объясняется в разделе предварительная загрузка текстур OpenGLES в другом потоке, есть два отдельных шага: создание растровых изображений и загрузка растровых изображений. В большинстве случаев вам должно быть хорошо, просто сделав создание растрового изображения на вторичном потоке, что довольно просто.

Если вы испытываете падение кадров при загрузке текстур, вызовите texImage2D из фонового потока. Для этого вам нужно создать новый контекст OpenGL, который разделяет его текстурами с потоком рендеринга, потому что каждому потоку нужен его собственный контекст OpenGL.

EGLContext textureContext = egl.eglCreateContext(display, eglConfig, renderContext, null);

Получение параметров для eglCreateContext немного сложнее. Вам нужно использовать setEGLContextFactory на вашем SurfaceView, чтобы подключиться к созданию EGLContext:

@Override
public EGLContext createContext(final EGL10 egl, final EGLDisplay display, final EGLConfig eglConfig) {
     EGLContext renderContext = egl.eglCreateContext(display, eglConfig, EGL10.EGL_NO_CONTEXT, null);

     // create your texture context here

     return renderContext;
}

Затем вы готовы запустить поток загрузки текстуры:

public void run() {
    int pbufferAttribs[] = { EGL10.EGL_WIDTH, 1, EGL10.EGL_HEIGHT, 1, EGL14.EGL_TEXTURE_TARGET,
            EGL14.EGL_NO_TEXTURE, EGL14.EGL_TEXTURE_FORMAT, EGL14.EGL_NO_TEXTURE,
            EGL10.EGL_NONE };

    EGLSurface localSurface = egl.eglCreatePbufferSurface(display, eglConfig, pbufferAttribs);
    egl.eglMakeCurrent(display, localSurface, localSurface, textureContext);

    int textureId = loadTexture(R.drawable.waterfalls);

    // here you can pass the textureId to your 
    // render thread to be used with glBindTexture
}

Я создал рабочую демонстрацию приведенных фрагментов кода в https://github.com/perpetual-mobile/SharedGLContextsTest.

Это решение основано на многих источниках в Интернете. Самые влиятельные, где эти три:


2 depp1983 [2011-10-07 15:47:00]

"Должен быть способ вызова функций GL вне функции инициализации". - Да. Просто скопируйте указатель на gl и используйте его где угодно.

"Просто обязательно используйте OpenGL в основном потоке". Очень важно. Вы не можете вызвать в своем игровом движке (который может быть в другом потоке) функцию текстурной загрузки, которая не синхронизируется с gl-нитью. Установите флаг, чтобы сигнализировать gl-thread для загрузки новой текстуры (например, вы можете поместить функцию в OnDrawFrame (GL gl), которая проверяет, должна ли быть загружена новая текстура.


0 Ixx [2013-02-24 01:35:00]

Нашел решение для этого, что на самом деле очень просто: после загрузки растрового изображения (в отдельном потоке), сохраните его в переменной экземпляра и в методе draw, проверьте, инициализировано ли оно, если да, загрузите текстуру. Что-то вроде этого:

if (bitmap != null && textureId == -1) {
    initTexture(gl, bitmap);
}

0 Saxon Druce [2014-04-03 03:17:00]

Чтобы добавить в ответ Роджи, если вы хотите использовать контекст OpenGL ES 2.0, для создания контекста используйте следующее:

final int EGL_CONTEXT_CLIENT_VERSION = 0x3098;
int[] contextAttributes = 
    { EGL_CONTEXT_CLIENT_VERSION, 2, EGL10.EGL_NONE };
EGLContext renderContext = egl.eglCreateContext(
    display, config, EGL10.EGL_NO_CONTEXT, contextAttributes);

Вам по-прежнему нужно вызывать setEGLContextClientVersion(2), так как это также используется конфигурационным конфигуратором по умолчанию.

Это основано на списке атрибутов в eglCreateContext