пятница, 16 октября 2009 г.

Multithreading in OpenGL API

Как известно, OpenGL имеет некоторые неудобства для работы в разных потоках, по сравнению с Direct3D. Сам недавно столкнулся с этими неудобствами на платформе Windows.
Согласно документации MSDN, для каждого потока в котором будет работа с OpenGL API, должен быть свой текущий контекст рендеринга, установку текущего контекста
осуществляется с помощью функции wglMakeCurrent.
Если это не так, то при любом обращении к функциям OpenGL API будет ошибка GL_INVALID_OPERATION, ну а дальше нарушенный доступ к памяти и далее поведение
программы не определено.
Для решения этой проблемы, нужно создать для нового потока новый контекcт воспроизведения, используя функцию wglCreateContext.
В качестве контекста окна можно передать контекст окна приложения, хотя по некоторым советам, следует создать дополнительное маленькое окно размером 1x1 пиксель.
Хотя у меня работало и без дополнительного окна. Далее, нужно что-бы все изменения между потоками были известны друг другу. К примеру, создается
текстура, вершинный или индексный буфер и т.д. в одном потоке, а использоваться будет в другом. Осуществить это нужно с помощью функции wglShareLists,
причем тут дисплейные списки в описании функции я не знаю.
Лучше сделать расшаривание контекстов друг на друга, хотя все зависит от задачи, т.е. если есть к примеру есть load_context и render_context, которые используются в потоке загрузки и рендеринга соответственно, то пара вызовов:
wglShareLists(load_context, render_contex);
wglShareLists(render_contex, load_context);

обеспечат видимость изменений между этими потоками.
В случае неудачи вызова wglShareLists у меня GetLastError возвращает ошибку, строковое соответствие полученное через FormatMessage было таким:
"невозможно создать файл так как он уже существует", почему это так, для меня загадка.
При завершении каждого потока нужно не забыть освободить связанный с ним контекст.