Плагин OpenGL приводит к сбою Chrome при изменении видимой области

Я разрабатываю плагин с использованием FireBreath для Windows (на данный момент), который, среди прочего, отображает канал веб-камеры с использованием OpenGL. Я использую оконный плагин и рисую из отдельного потока. Код можно посмотреть здесь:

Заголовочный файл

https://github.com/EvilTengil/kinect-at-home-plugin/blob/0007beecf136ff2e5e1aa50be94d4906447a8f43/Win/KinectAtHomeWin.h

Исходный файл

https://github.com/EvilTengil/kinect-at-home-plugin/blob/0007beecf136ff2e5e1aa50be94d4906447a8f43/Win/KinectAtHomeWin.cpp

(Не обращайте внимания на странный код в onWindowResized, это просто проверка, которая осталась в коммите.)

Проблема в том, что как только размер окна браузера изменяется так, что видимая область плагина изменяется или расширение каким-то образом прокручивается за пределы видимой области поля прокрутки, плагин в Chrome падает. У меня не установлен Firefox, но я предполагаю, что это NpApi, так как он работает в Internet Explorer.

Я считаю, что происходит то, что Chrome выпускает и создает новый HDC всякий раз, когда изменяются видимые размеры плагина. Это, вероятно, приводит к тому, что контекст рендеринга недействителен, но он все еще используется в плагине, и это вызывает сбой.

Я заметил, что когда это происходит, вызывается NPP_SetWindow get, но эти вызовы игнорируются в NpapiPluginModule_NPP.cpp, поэтому я не могу подключиться к этому событию.

У меня есть Google уже несколько часов, но я не нашел никакой помощи. У кого-нибудь есть опыт в этом?

У меня есть идея, что это могло бы сработать, если бы я создал свое собственное дочернее окно для окна плагина, где я мог бы обрабатывать свой собственный контроллер домена. Я провел несколько быстрых тестов, которые не увенчались успехом, вероятно, из-за моих хромых навыков работы с Win32. Но может ли это работать с некоторой дополнительной работой? У меня есть еще одна идея - как-то отслеживать видимую область, но я еще не изучал ее.


person Daniel    schedule 18.02.2012    source источник
comment
Пробежался глазами, но копать глубже времени нет. Достаточно просто настроить OGL без рисования, что происходит в FF и Chrome и не происходит в FF, когда отключены сторонние плагины. Отключение подкласса окон FB не помогает. Подключите Visual Studio с настроенным сервером символов Microsoft (возможно, также Mozillas), и вы увидите, что он падает с переполнением стека при обработке некоторых оконных процессов (очевидно, бесконечная рекурсия). Кстати, здесь SetWindow проходит через FB::NpapiPluginWin.   -  person Georg Fritzsche    schedule 20.02.2012


Ответы (1)


Недействительные дескрипторы Windows не должны приводить к сбою программы. Но OpenGL, а именно его расширения, требуют некоторых особых мер предосторожности, особенно если основная программа также использует OpenGL.

Любой плагин или DLL, использующий OpenGL, должен заботиться о том, чтобы привести необходимые ресурсы в нормальное состояние перед их использованием и вернуть их после завершения. Для OpenGL это означает, что каждый раз, прежде чем вы начнете его использовать, вы должны перепривязывать свой контекст:

HDC hOldDC = wglGetCurrentDC();
HRC hOldContext = wglGetCurrentContext();

 // first unbind old context/DC from current thread
wglMakeCurrent(NULL, NULL);

 // then bind our context
wglMakeCurrent(hMyDC, hMyContext);

 // this is essential, as in Windows the addresses of extensions
 // may depend on the active context, so you must reinitialise
 // extension function pointers!
reinitialize_extensions();

/* NOW USE OPENGL FUNCTION

 // cleaning up once we're done:
wglMakeCurrent(NULL, NULL);
wglMakeCurrent(hOldDC, hOldRC);
// remember that we also need to reset extension
// function pointers to the other context
reinitialize_extensions();

Поскольку в функциях расширения Window указатели зависят от контекста, имеет смысл поместить их в структуру и вызывать через нее. Это сохраняет всю вещь повторной инициализации расширения. В C++ для этого можно обернуть весь контекст OpenGL в класс.

Помните, что вам нужно проходить эту настройку/разборку каждый раз, когда ваш плагин вызывается через NP-API.

person datenwolf    schedule 18.02.2012
comment
Просто из любопытства, у вас действительно были проблемы из-за недействительных указателей расширений? Я годами выполнял GL в Windows без проблем с этим, но, возможно, мне повезло из-за выделенного оборудования, и я не слишком часто возился с несколькими одновременными контекстами. - person rotoglup; 19.02.2012
comment
OP имеет код установки и рисования OpenGL в отдельном потоке и документы говорят, что вы получаете один текущий контекст GL для каждого потока - person Georg Fritzsche; 19.02.2012
comment
@GeorgFritzsche: Если ОП последовал моему совету, он также получит поддержку многопоточности. Суть многопоточности OpenGL заключается в том, что контекст должен быть активен только в одном потоке за раз и что каждый поток имеет ровно один контекст. Но контекст может прекрасно мигрировать между потоками. Приведенный выше код также позаботится о безопасности многопоточности. - person datenwolf; 19.02.2012
comment
Хм, я тоже это понял, но он создает новый контекст в новом потоке, никогда ничего не перенося и не активируя другой контекст в этом потоке. Для справки: я добавил вышеизложенное в репро-кейс, и это не меняет поведение здесь. - person Georg Fritzsche; 20.02.2012
comment
@GeorgFritzsche: О, значит, он несколько раз пытается установить PIXELFORMATDESCRIPTOR в одном и том же окне? Это может быть одной из причин, поскольку PFD окна может быть установлен только один раз. - person datenwolf; 20.02.2012
comment
По крайней мере, с Firefox это только один раз, я предполагаю, что Chrome ведет себя примерно так же. Согласно моему комментарию к вопросу, похоже, что оконные процессы браузеров и WGL могут мешать друг другу. - person Georg Fritzsche; 20.02.2012