Программирование игр, создание игрового движка, OpenGL, DirectX, физика, форум
GameDev.ru / Программирование / Подсказки / wglShareList и миф рендера в несколько окон

wglShareList и миф рендера в несколько окон

Автор:

На написание этой подсказки меня сподвигло открытие полученное в результате вдумчивого чтения мануалов по OpenGL.
Традиционно разрабатываю системы, способные рендерить изображение сразу в несколько окон.
И гугл(в том числе активно ссылаясь на gamedev.ru) говорит, что для рендера в несколько окон нужно в каждом окне создавать OpenGL Rendering Context и соединять их с помощью wglShareList.
Это в корне не верно.

Правильный способ рисования в несколько окон сводится к тому, чтобы создать один OpenGL Rendering Context, установить всем окнам общий формат пикселя и при отрисовке в каждом окне выставлять ранее созданный контекст:
wglMakeCurrent(CurrentWindow.HDC, RC);

Большая часть OpenGL программистов ошибочно полагает, что создавая контекст они привязывают его к конкретному HDC. Это не так.
Когда мы создаем контекст – мы лишь указываем ему тип HDC под который данные контекст необходимо создать. HDC  в этой ситуации используется лишь как набор параметров для создания контекста. Никакой привязки не происходит и контекст может работать с любым другим HDC. Главное, чтобы этот HDC имел тот же формат пикселя, что и HDC с настройками которого создавался контекст.

Использование wglShareList для задачи рендера в несколько окон в принципе возможно, но может привести к трудноуловимым багам.
Например, wglShareList требует, чтобы все контексты были созданы ДО того, как будут загружены какие-либо данные в видеопамять.
При этом требование не жесткое, и все вполне может работать на одних машинах и не работать на других.
В любом случае – wglShareList создан для других целей и решает другие задачи.

21 января 2013

#OpenGL

Комментарии:
Страницы: 1 2 3 Следующая »
SunnyBunnyПостоялецwww21 окт. 20139:15#1
Полезная подсказка.
У меня не получается рисовать в несколько окон с vsync-ом. Свопаю окна по очереди, фпс падает в соответствии с количеством окон: 1 окно - 60 фпс, 2 окна - 30 фпс, 3 окна - 20 фпс и т.д.
ОС - windows xp. Подскажите, как делать правильно?
eXmireПостоялецwww21 окт. 201310:45#2
SunnyBunny
> Полезная подсказка.
Наоборот.

@!!ex
> Правильный способ рисования в несколько окон...
Правильно не рисовать в несколько окон. И уж тем более не вызывать wglMakeCurrent в каждом кадре, ибо дорого.

MrShoorУчастникwww21 окт. 201310:57#3
eXmire
Правильно не рисовать в несколько окон. И уж тем более не вызывать wglMakeCurrent в каждом кадре, ибо дорого.

Ну иногда нужно. В особенности превьюшки всякие в диалоговых окнах и т.п. Правда я в этом случае создаю отдельный рендерконтекст, и рисую в нем, ибо по факту общих данных минимум (а бывает и вообще нет копирования данных). Но скакать рендер контекстом по окнам я соглашусь, тоже не дело. Хотя технически можно конечно, ну и от задачи зависит. Если в той же превьюшке нужно только на WM_PAINT рисовать, когда ОС требует перерисовки - то можно и скакнуть 1 раз несколько секунд/минут.
eXmireПостоялецwww21 окт. 201311:12#4
MrShoor
> Ну иногда нужно. В особенности превьюшки всякие в диалоговых окнах и т.п.
Об этом да, забыл. В случае диалоговых окон переключение контекста по окнам подойдет, там на производительности это не скажется.
gkv311Постоялецwww21 окт. 201312:10#5
SunnyBunny
У меня не получается рисовать в несколько окон с vsync-ом. Свопаю окна по очереди, фпс падает в соответствии с количеством окон: 1 окно - 60 фпс, 2 окна - 30 фпс, 3 окна - 20 фпс и т.д.
ОС - windows xp. Подскажите, как делать правильно?

В Windows 7 и Linux оно иногда умудряется рисовать с V-Sync из одного потока в несколько окошек без кратного проседания FPS.
Возможно, функция свопа возвращает несколько раньше, нежели новый кадр начинает выводится на монитор.

В Windows XP, по всей видимости, функция swap'a для первого окна возвращается строго после, и следующее окно в очереди ждёт следующего синхрокадра.
Поэтому своп приводит к кратному падению FPS.

Вообще opengl32.dll имеет малодокументированную функцию wglSwapMultipleBuffers, которая позволяет свопать сразу список окошек.
Но увы, эту функцию вендоры не перебивают и всё что она делает - в цикле вызывает обычный своп для каждого окна.
Вендоры имеют собственные реализации подобной штуки через расширения вида WGL_NV_swap_group, но доступны они только для профессиональных карт.

По сути, единственный способ избежать падения FPS, который я вижу - рисовать каждое окно в отдельных потоках (что вызовет дополнительные проблемы, если хочется шарить ресурсы).

@!!exПостоялецwww21 окт. 201319:23#6
eXmire
> Правильно не рисовать в несколько окон.
И как же тогда делать многооконный рендер, если не секрет? :)
@!!exПостоялецwww21 окт. 201319:52#7
gkv311
Можно попробовать в отдельных потоках только Swap делать. А рисовать все как и обычно.
@!!exПостоялецwww21 окт. 201319:54#8
MrShoor
> равда я в этом случае создаю отдельный рендерконтекст
Ну то есть ты не понял что там вообще написано?
Создание отдельных рендер контекстов - это костыль. Который может приводить(и приводит) к проблемам.
Собственно я раньше сам делал многооконный рендер через отдельный контекст на каждое окно. Пока не отловил проблем и не начал копаться. Пока не выяснил, что создание рендер контекстов для отдельных окон - это не правильное использовани контекстов.

eXmire
> И уж тем более не вызывать wglMakeCurrent в каждом кадре, ибо дорого.
Не дороже рендера в отдельные контексты.

gkv311Постоялецwww21 окт. 201322:08#9
@!!ex
что создание рендер контекстов для отдельных окон - это не правильное использовани контекстов.

Я бы не стал так категорично говорить.

Прочитав статью полгода назад, я решил переделать свой рендерер на Windows и Linux под использование одного контекста (на Mac OS X остановился - ибо лень).
За исключением дополнительных заморочек (таких как проставление каждый кадр вьюпорта), никаких существенных отличий в поведении я не заметил.
Проблем никаких не решило, новых, к счастью, не добавилось.

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

eXmireПостоялецwww21 окт. 201322:14#10
@!!ex
> И как же тогда делать многооконный рендер, если не секрет? :)
Не делать.

@!!ex
> Не дороже рендера в отдельные контексты.
Тут дело уже не в дороговизне, а в том, что дерганье OpenGL из разных потоков одновременно — прямая дорога к багам драйвера и внутренним синхронизациям.

@!!exПостоялецwww21 окт. 201322:27#11
gkv311
> Проблем никаких не решило
Повторюсь - текст написан не с бухты барахты. Текст написан на основе реального опыта.
Проблемы решаются. В частности, одна из проблем в тексте написана. Остальные сейчас уже не вспомню.

eXmire
> Тут дело уже не в дороговизне, а в том, что дерганье OpenGL из разных потоков
> одновременно — прямая дорога к багам драйвера и внутренним синхронизациям.
В тексте ни слова про потоки. Речь об отдельных окнах. А не о многопоточности.

eXmire
> Не делать.
Вот реальное приложение на котором, собственно, обкатывался подход:

Как это реализовать без отдельных окон и рендера в них?

gkv311Постоялецwww21 окт. 201322:50#12
@!!ex
Использование wglShareList для задачи рендера в несколько окон в принципе возможно, но может привести к трудноуловимым багам.
Например, wglShareList требует, чтобы все контексты были созданы ДО того, как будут загружены какие-либо данные в видеопамять.
При этом требование не жесткое, и все вполне может работать на одних машинах и не работать на других.

Ладно, соглашусь, встречал проблемы с расшариванием контекстов.
Один из не самых старых выпусков Catalyst стал отказывать шарить контексты для окошек, созданных на разных мониторах.
Пришлось прикручивать workaround - создавать все дополнительные окна там же, где и главное окно, а перед Show двигать его на правильное место.

Хотя с "загружены какие-либо данные в видеопамять" - это какое-то странное утверждение.
Подобные детские проблемы я наблюдал, когда wglShareList для нового контекста звался не в то время (при этом важно, чтобы не создать никаких ресурсов до wglShareList в новом контексте - в старом как раз ресурсы могут уже быть).

@!!exПостоялецwww21 окт. 201323:04#13
http://www.opengl.org/wiki/Platform_specifics:_Windows#wglShareLists
The best time to call wglShareLists is after creating the GL contexts you want to share, but before you create any objects in either of the contexts. If you create objects, then there is a chance that wglShareLists will fail.

Внезапно это не мои фантазии, а вполне себе из доки по OGL.

MrShoorУчастникwww22 окт. 20136:07#14
@!!ex
> Ну то есть ты не понял что там вообще написано?
> Создание отдельных рендер контекстов - это костыль. Который может приводить(и
> приводит) к проблемам.
> Собственно я раньше сам делал многооконный рендер через отдельный контекст на
> каждое окно. Пока не отловил проблем и не начал копаться. Пока не выяснил, что
> создание рендер контекстов для отдельных окон - это не правильное использовани
> контекстов.
Нука нука? Какие проблемы в создании второго контекста и рендера в него?

> Вот реальное приложение на котором, собственно, обкатывался подход:
> Как это реализовать без отдельных окон и рендера в них?
Я рабочий стол делал общим, делал окошко на весь рабочий стол, и рендерил в него. Надо сделать 8 рендеров в одно окно? Юзаем glViewport. На порядок быстрее чем скакать контекстом, и реально огрести проблемы, как тут уже сказали с glSwapBuffers и VSync-ом.

Страницы: 1 2 3 Следующая »

/ Форум / Программирование игр / Графика

Тема в архиве.

2001—2017 © GameDev.ru — Разработка игр