OpenGL
Мне нужно выделить работу с OpenGL в отдельный поток (thread). Как мне это сделать ?
Основные положения многопоточности OpenGL таковы:
Каждый поток в OpenGL может иметь свой, активный контекст устройства (RC), но только один.
Именно туда поступают все gl-команды из потока. Контекст не может быть активным одновременно у нескольких потоков. Для этого существует функция wglMakeCurrent. Однако, поскольку периодические активизация/деактивизация контекста могут серьёзно замедлить программу, лучше всего будет "захватывать" контекст при запуске потока, и "отпускать" при его завершении. Например:
DWORD WINAPI ThreadFunc(LPVOID lpData) { // Получение входных параметров из блока, передаваемого по адресу lpData hDC=.... hRC=.... // Получить контекст в своё распоряжение wglMakeCurrent(hDC,hRC); // Код потока ..... .... // // "Отпустить" контекст wglMakeCurrent(hDC,NULL); return 0; }
Разумеется, нужно самому предусмотреть синхронизацию этого и основного потоков, а также механизм передачи "задания".
Есть ещё один важный момент. Если все текстуры загружены и дисплейные списки (display lists - DL) созданы ещё ДО запуска такого потока - прекрасно; если же их нужно подгружать и удалять в процессе работы, нужно ещё кое-что.
Можно создать ВТОРОЙ контекст устройства (в невидимом окне размером 1x1 пиксел), который будет активным у основного потока программы. Для объединения адресных пространств двух контекстов используется wglShareLists(dest,source).
Начиная с OpenGL версии 1.1, эта функция импортирует не только адресное пространство дисплейных списков (glGenLists,glDeleteLists), но и текстурных объектов (glGenTextures,glDeleteTextures). Все изменения, сделанные в одном контексте, будут автоматически отображаться в другой.
wglShareLists нужно вызывать сразу же после создания контекстов, пока ещё не определено никаких текстур и DL. Желательно также, но совсем не обязательно, чтобы оба контекста имели одинаковый формат (SetPixelFormat).
Примечание: многопоточность OpenGL невозможна на враперах вроде 3Dfx GL / miniGL из-за ограничений их нижнего этажа, GLide. В этих случаях контексты будут успешно создаваться, и каждый поток получит контекст в своё распоряжение, однако только один из них будет реально подключен к устройству (последний созданный, или тот, который сделали текущим для какого-либо потока с помощью функции wglMakeCurrent в последнюю очередь).
Попытка выводить что-то из других контекстов вызовет ошибку защиты памяти в коде враппера.
Оставить комментарий
Комментарии
девайс контекст (hDC) можно создать и второй контекст рендеринга (hRC2)[/quote]
без невидимого окна никак! оно обязаетльно! нельзя создавать два контекста рендеринга на один девайс-контекст...
//Main Thread:
//...
hRC1 = wglCreateContext(g_hDC);
hRC2 = wglCreateContext(g_hDC);
wglShareLists(hRC2, hRC1);
wglMakeCurrent(g_hDC, hRC1);
//Secondary Thread:
//...
wglMakeCurrent(g_hDC, hRC2);
Не нужно создавать невидимого окна. Используя
девайс контекст (hDC) можно создать и второй контекст рендеринга (hRC2) и расшарить его для
контекста потока рендера(hRC1), тогда установив контексты hRC1 и hRC2 каждый как текущий в своём потоке, можно будет рендерить OpenGL-ом из двух потоков без проблем.
//...
hRC1 = wglCreateContext(hDC);
hRC2 = wglCreateContext(hDC);
wglShareLists(hRC2, hRC1);
wglMakeCurrent(hRC1);
//Secondary Thread:
//...
wglMakeCurrent(hRC2);