Я пишу приложение для просмотра 3D-моделей в качестве хобби-проекта, а также как тестовую платформу для тестирования различных методов рендеринга. Я использую SDL для обработки управления окнами и событий и OpenGL для 3D-рендеринга. Первая итерация моей программы была однопоточной и работала достаточно хорошо. Тем не менее, я заметил, что однопоточная программа заставила систему стать очень медлительной/отсталой. Мое решение состояло в том, чтобы переместить весь код рендеринга в другой поток, освободив тем самым основной поток для обработки событий и не позволяя приложению перестать отвечать на запросы.
Это решение работало с перерывами, программа часто терпела крах из-за изменения (и, на мой взгляд, странного) набора ошибок, поступающих в основном из системы окон X. Это заставило меня подвергнуть сомнению мое первоначальное предположение, что до тех пор, пока все мои вызовы OpenGL имели место в потоке, где был создан контекст, все должно быть выполнено. Проведя большую часть дня, ища в интернете ответ, я полностью запятнана.
Более кратко: возможно ли выполнить 3D-рендеринг с использованием OpenGL в потоке, отличном от основного потока? Могу ли я по-прежнему использовать кросс-платформенную библиотеку окон, такую как SDL или GLFW с этой конфигурацией? Есть ли лучший способ сделать то, что я пытаюсь сделать?
До сих пор я развивался в Linux (Ubuntu 11.04) с использованием С++, хотя мне также нравится Java и Python, если есть решение, которое лучше работает на этих языках.
ОБНОВЛЕНИЕ: В соответствии с запросом, некоторые пояснения:
- Когда я говорю "Система становится вялой", я имею в виду, что взаимодействие с рабочим столом (перетаскивание окон, взаимодействие с панелью и т.д.) становится намного медленнее, чем обычно. Перемещение моего окна приложения занимает время порядка секунд, а другие взаимодействия достаточно медленны, чтобы раздражать.
- Что касается помех в диспетчере окон компоновки... Я использую оболочку GNOME, которая поставляется с Ubuntu 11.04 (теперь отстоит от Unity...), и я не мог найти никаких параметров для отключения эффектов рабочего стола, таких как в предыдущих распределениях. Я предполагаю, что это означает, что я не использую диспетчер окон компоновки... хотя я мог бы ошибаться.
- Я считаю, что "ошибки X" являются ошибками сервера из-за сообщений об ошибках, которые я получаю на терминале. Подробнее см. Ниже.
Ошибки, которые я получаю с многопоточной версией моего приложения:
XIO: фатальная ошибка IO 11 (ресурс временно недоступен) на сервере X ": 0.0" после 73 запросов (73 известных обработанных) с оставшимися 0 событиями.
X Ошибка неудачного запроса: BadColor (недопустимый параметр Colormap) Основной служебный код отказавшего запроса: 79 (X_FreeColormap) Идентификатор ресурса в неудавшемся запросе: 0x4600001 Серийный номер отказавшего запроса: 72 Текущий серийный номер в потоке вывода: 73
Игра:../../src/xcb_io.c:140: dequeue_pending_request: Ошибка утверждения `req == dpy- > xcb- > pending_requests '. Отменено
Я всегда получаю одну из трех ошибок, которые я получаю, по-видимому, случайным образом, что (на мой взгляд), похоже, подтвердит, что моя проблема действительно связана с моим использованием потоков. Имейте в виду, что я учусь, когда я иду, так что есть очень хороший шанс, что по моему невежеству у меня есть что-то довольно глупое на этом пути.
РЕШЕНИЕ: Для тех, кто имеет подобную проблему, я решил проблему, переместив мой вызов на SDL_Init(SDL_INIT_VIDEO)
в поток рендеринга и заблокировав инициализацию контекста с помощью мьютекса. Это гарантирует, что контекст создается в потоке, который будет его использовать, и предотвращает запуск основного цикла до завершения задач инициализации. Упрощенная схема процедуры запуска:
1) Основной поток инициализирует struct
, который будет разделяться между двумя потоками и который содержит мьютекс.
2) Основная нить порождает поток рендеринга и засыпает на короткий период (1-5 мс), давая время рендеринга для блокировки мьютекса. После этой паузы основной поток блокируется при попытке блокировки мьютекса.
3) Render thread блокирует мьютекс, инициализирует подсистему видео SDL и создает контекст OpenGL.
4) Render thread разблокирует мьютекс и входит в его "цикл рендеринга".
5) Основной поток больше не блокируется, поэтому он блокирует и разблокирует мьютекс до завершения этапа инициализации.
Обязательно прочитайте ответы и комментарии, там есть много полезной информации.