Есть ли способ безопасно связать текстуру с использованием OpenGL в рабочем потоке приложения Qt GUI? - PullRequest
6 голосов
/ 13 сентября 2011

В настоящее время я работаю над проектом программного обеспечения с графическим интерфейсом для визуализации 3D-сцен с использованием Qt. Графический интерфейс позволяет пользователю загружать пакеты 3D-файлов данных, таких как .obj, с некоторой поддержкой .mtl и .stl, а также 2D-файлы изображений в сцену в виде объектов класса SceneObject, которые отображаются в виджете, производном от QGLWidget.

Однако, когда я загружаю их в пакетном режиме в главном потоке графического интерфейса, длительное время загрузки приводит к зависанию графического интерфейса, что ужасно. Я попытался выполнить загрузку в отдельном потоке, но есть одна большая хитрость: при загрузке текстур или файлов изображений .obj я также буду выполнять связывание с помощью OpenGL glBindtexture () сразу после загрузки каждого изображения или текстуры, так что мне нужно только сохранить идентификаторы текстуры в каждом экземпляре SceneObject. Когда я пытался выполнить загрузку в рабочем потоке, вся программа просто зависала.

Я читал, что каждый поток может получить доступ только к одному контексту OGL, и переключение контекста между потоками - это один, но опасный способ достичь того, что я хотел сделать. Другим возможным способом было бы выполнить привязку текстур к потоку GUI после завершения загрузки, но это означало бы полную переработку моего класса SceneObject: (

Кто-нибудь может дать мне несколько советов о том, как реализовать поток загрузки для загрузки ресурсов в сцену OpenGL?

1 Ответ

5 голосов
/ 13 сентября 2011

Я также выполню привязку с помощью OpenGL glBindtexture () сразу после загрузки каждого изображения или текстуры, так что мне нужно только сохранять идентификаторы текстуры в каждом экземпляре SceneObject.Когда я пытался выполнить загрузку в рабочем потоке, вся программа просто зависала.

Контекст OpenGL может быть активным только в одном потоке за раз.Вообще многопоточная работа OpenGL обычно становится главным кошмаром, чтобы получить право.В вашем случае вы намерены делегировать загрузку ресурсов.Раньше, до того, как существовал буферный объект, вы делали это, создавая вспомогательный контекст и разделяя его «списки» с основным контекстом.

Сегодня у нас есть кое-что лучше: буферизировать объекты.Буферный объект позволяет отправлять данные в OpenGL асинхронным способом.Это похоже на

glGenBuffers(...);
glBindBuffer(...);
glBufferData(..., size, usage);
void *p = glMapBuffer(...);
memcpy(p, data, size);
glUnmapBuffer(...);
glTexImage / glDrawPixels / etc.

. Важно понимать, что адресное пространство, выделенное glMapBuffer, распределяется между потоками.Таким образом, вы можете указать контексту OpenGL в основном потоке для сопоставления объекта буфера, посылая сигнал вашему рабочему потоку с выделением.Затем рабочий поток заполняет данные и после завершения отправляет сигнал потоку контекста OpenGL для отмены отображения.

EDIT для многопоточности

Так что для этого вам нужнореализовать некоторые обработчики сигналов с обеих сторон (псевдокод)

signal OpenGLThread::mapPixelBufferObjectForWrite(ImageLoader il):
    glGenBuffers(1, &self.bufferId)
    glBindBuffer(GL_PIXEL_UNPACK_BUFFER, self.bufferId)
    glBufferData(GL_PIXEL_UNPACK_BUFFER, il.unpackedImageSize, NULL, GL_STATIC_DRAW)
    BufferObjectMapping map(glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY))
    send_signal(target_thread = workerthread, target_signal_handler = workerthread::loadImageToBuffer(map, il), signal_on_finish = self.unmapPixelBufferObjectWriteFinishedGenTexture(map))

signal IOThread::loadImageToBuffer(BufferObjectMapping map, ImageLoader il):
    /* ... */

signal OpenGLThread::unmapPixelBufferObjectWriteFinishedGenTexture(BufferObjectMapping map, ImageLoader il):
    if(map.mapping_target == GL_PIXEL_UNPACK_BUFFER)
    glBindBuffer(GL_PIXEL_UNPACK_BUFFER, self.bufferId)
    glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER)
    glGenTextures(1, &il.textureId)
    glBindTexture(il.target, il.textureId)
    for mipmaplevel in il.levels
        glTexImage2D(il.target, mipmaplevel, il.internalformat, il.width, il.height, il.border, il.format, il.type, mipmaplevel.offset)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...