Редактировать: ниже я разместил хорошее решение общей проблемы разделения средств визуализации.
Недавно я играл с OpenGL в многопоточной среде X11. Я нашел следующий учебник, который компилирует , ссылки и работает нормально.
Но затем я столкнулся со странной проблемой после попытки адаптировать код для своих нужд.
В учебнике порядок вызова XCreateWindow, glXCreateContext, XSelectInput и XSetWMProtocols следующий:
param[i].win = XCreateWindow(param[i].d_, root, 200,200,
300,200, 0, visInfo->depth, InputOutput, visInfo->visual,
CWColormap,
&windowAttr);
param[i].ctx = glXCreateContext(param[i].d_, visInfo, NULL, True);
XSelectInput(d, param[i].win, StructureNotifyMask);
XSetWMProtocols(d, param[i].win, &(delMsg), 1);
Обратите внимание, что XCreateWindow и XSelectInput/XSetWMProtocols используют разные подключения дисплея.
Однако при изменении порядка вызовов
param[i].win = XCreateWindow(param[i].d_, root, 200,200,
300,200, 0, visInfo->depth, InputOutput, visInfo->visual,
CWColormap,
&windowAttr);
XSelectInput(d, param[i].win, StructureNotifyMask);
XSetWMProtocols(d, param[i].win, &(delMsg), 1);
param[i].ctx = glXCreateContext(param[i].d_, visInfo, NULL, True);
программа не работает с
X Ошибка неудачного запроса: BadWindow (неверный параметр окна)
Основной код операции неудачного запроса: 2 (X_ChangeWindowAttributes)
Идентификатор ресурса в неудачном запросе: 0x5000002 Серийный номер неудачного запроса: 17 Текущий серийный номер в выходном потоке: 18
что, по-видимому, вызвано XSetWMProtocols.
Поскольку использовались разные подключения дисплея, я не удивлюсь, если все это вообще не сработает. Но каким-то образом после вызова glXCreateContext все кажется волшебным образом прекрасным.
Я относительно новичок в программировании X11/GLX, я что-то пропустил? Какую магию выполняет glXCreateContext? Или что-то еще случилось? Или, может быть, мне просто нужно двигаться дальше, потому что OpenGL и многопоточность всегда вызывают проблемы.
Мое решение:
Я был ленив и просто использовал подход из учебника. Это работало до тех пор, пока в мой проект не был добавлен фритайп, что внезапно снова привело к сбою BadWindow. Таким образом, даже если кажется, что все в порядке, когда вы работаете из разных потоков, X11 серьезно возится с памятью, пока вас нет рядом. (Это был не я, я проверял с помощью valgrind)
Мое текущее решение как н.м. прокомментировал: я поместил все в поток GUI (вызовы X11 и GL/GLX), чьи ресурсы никогда не доступны другим потокам. Однако необходимо помнить о двух вещах, поскольку это может замедлить цикл рендеринга:
- Медленная обработка сообщений задерживает рендеринг (как указано ilmale ниже)
- Медленный рендеринг задерживает обработку сообщений (моя проблема)
Первую проблему можно легко решить. Создайте очередь или список stl или любой другой контейнер, в котором вы ставите в очередь соответствующие XEvents для логики вашего приложения, а затем получаете их из другого потока. Просто убедитесь, что ваш STL является потокобезопасным, и, если сомневаетесь, реализуйте свою собственную очередь. С условием ожидания, установленным для размера контейнера, вы даже можете имитировать блокирующие вызовы, такие как XNextEvent.
Вторая проблема каверзная. Вы можете возразить, что если рендерер работает со скоростью 1 кадр/с или медленнее, игра или приложение в любом случае бесполезны. Это правда. Но было бы неплохо, если бы вы могли обработать какой-нибудь сигнал уничтожения (например, атом окна уничтожения), даже если у вас 0,1 кадра в секунду. Единственное решение, которое пришло мне в голову, это проверка новых сообщений после рендеринга каждой тысячи спрайтов или около того. Отправьте их в свой контейнер и продолжите рендеринг. Конечно, в этом случае вы никогда не сможете позволить потоку рендеринга запускать пользовательские скрипты или другой неизвестный код в любое время. Но я предполагаю, что это сделало бы идею отделения рендеринга от других потоков бессмысленной.
Надеюсь это поможет.
: