Войти
ПрограммированиеФорумГрафика

Асинхронная загрузка текстур Opengl

Страницы: 1 2 3 Следующая »
#0
(Правка: 9:22) 9:19, 25 фев. 2021

Понимаю что тема не раз поднималась но все же решил спросить про приемы которыми можно пользоваться когда пропускной способности канала при передаче текстур в память видеокарты не хватает. ОС Debian, OpenGL ver 2.0

Понимаю что Opengl может работать работать с контекстом только в одном потоке. Читал про:
1. Возможные оптимизации связанные с использованием сжатых текстур, применения glTexSubImage2D вместо glTexImage2D.

2. Разделяемые контексты для использования в разных потоках (например применительно к linux и qt:
https://www.linux.org.ru/forum/development/12559579)

3. Pixel Buffer Object - загрузка текстуры в память видеокарты должна проходить асинхронно но я для себя так и не уяснил как определить что загрузка завершена и можно вызывать glTexSubImage2D и использовать загруженную текстуру вместо старой?
Пример который нашел: http://www.songho.ca/opengl/gl_pbo.html

Вообщем кто сталкивался посоветуйте кто и чем пользовался и как лучше это делать?


#1
9:34, 25 фев. 2021

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

#2
(Правка: 10:01) 9:56, 25 фев. 2021

Suslik
Опишу задачу подробнее: карта земной поверхности состоящая из квадратных растровых изображений - тайлов. При изменении масштаба приходится грузить тайлы заново с другим масштабом. Текстурный кэш в этой ситуации не сильно спасает т.к. резко подрастает число тайлов требующих загрузки.
Перерисовка сцены происходит по таймеру один раз в секунду. Если буду пытаться ограничивать число тайлов прогружаемых при вызове таймера то это растянется надолго. Мысль была равномерно растянуть процесс загрузки между отрисовкой поверхности по таймеру. Вопрос с асинхронностью встал потому что кроме перерисовки карты по таймеру вызывается ряд других действий не связанных с картой и которые тоже требуют времени. Кроме того таймер вызывается в потоке отвечающем за gui - и тормозить его для решения задачи загрузки никак нельзя. Иначе будет глючит вся форма а не только карта....

#3
10:03, 25 фев. 2021

urii, тебе нужны мегатекстуры. Ищи на форуме, было много тем и статей.

#4
10:11, 25 фев. 2021

urii
Это ты изобрел мипмапы?

#5
10:22, 25 фев. 2021

У меня в (никак не доделаю, арг) движке это реализовано - обезъянничал с Unreal Engine 3.

Вот только асинхронная загрузка текстур - лишь надводная часть айсберга. Там целый гигантский велосипед менеджера ассетов. Поелику ещё желательно загрузку жпегов из PK3 и декодирование жпегов в raw выпнуть нафик из основного потока. И за нагрузкой следить, чтобы не просаживать fps но и не тянуть слишком долго. И за дедлоками в этом супе из тасков приглядывать.

TL;DR: это делается, но это не делается просто.

#6
(Правка: 10:42) 10:36, 25 фев. 2021

urii
Какого размера тайл? Грузи 1-10 тайлов кадр, будет нормально. (на Pci-Ex 4.0 16x).
Во второй поток можно вынести загрузку данных с диска. А заливку на ГПУ можно уже делать в основном потоке.

Вот я делал вообще в лоб, даже с диска была загрузка в основном потоке (правда это PCIEx SSD):

+ Показать

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

urii
> Pixel Buffer Object - загрузка текстуры в память видеокарты должна проходить асинхронно но я для себя так и не уяснил как определить что загрузка завершена
> и можно вызывать glTexSubImage2D и использовать загруженную текстуру вместо старой?
Фенсой, после загрузки в PBO. Но это не нужно. Для стриминга тебе нужно два PBO и две текстуры.
Заливаешь в PBO1. Копируешь PBO1 в TEX1. Рисуешь TEX2.
Заливаешь в PBO2. Копируешь PBO2 в TEX2. Рисуешь TEX1.

urii
> Перерисовка сцены происходит по таймеру один раз в секунду.
А не, у тебя что-то странное. Делай так:
0. Засекаю время
1. Посчитаю позицию, откуда показать
2. Гружу нужные тайлы
3. Рисую сцену
4. Жду, пока пройдет 1 секунда с засечки из пункто 0.

Опционально можно еще секундой ограничить время загрузки тайлов - те что не успели догрузиться за секунду - нарисовать в следующем тике.

#7
10:52, 25 фев. 2021

nes
Теперь давай представим себе 10ый масштаб это 2^10 =1024 изображений по горизонтали и столько же по вертикали. Каждое 256 х256 . Сколько памяти вам нужно чтобы загрузить масштабы от 0 до 10в виде одного изображения с мипмапами?

#8
11:44, 25 фев. 2021

urii
> Если буду пытаться ограничивать число тайлов прогружаемых при вызове таймера то это растянется надолго.
то есть ты считаешь, что если она будет загружаться асинхронно, то это бы затянулось менее надолго? если тебе надо загрузить N мегов в память со скоростью V мегов в секунду, то на это в сумме потребуется N/V времени: хоть ты их синхронно грузи, хоть асинхронно, хоть целиком, хоть кусочками. никакой разницы. вопрос в том, как остальному приложению не погобнуть на протяжение этих N/V секунд. так вот самый простой ответ — грузи небольшими кусками. загрузил кусок — дай остальному приложению обработать сообщения или чем оно там занимается. куски могут быть какими угодно мелкими (в разумных пределах), чтобы ты всегда успевал загрузить хотя бы один кусок за тик основного приложения.

#9
(Правка: 11:52) 11:47, 25 фев. 2021

urii
> Теперь давай представим себе 10ый масштаб это 2^10 =1024 изображений по
> горизонтали и столько же по вертикали. Каждое 256 х256
лол это вообще по-другому делается. фишка мипмапов в том, что тебе как раз НЕ нужно 1024 изображений по 256х256, потому что это тупо гораздо больше количества пикселей на экране, которые ты можешь отобразить. в идеале у тебя должно быть в памяти ровно столько текстурных текселей загружено, сколько пикселей на экране. ясное дело, в жизни так сделать не получится, но если у тебя текстура занимает на экране, скажем, 10х10 пикселей, то нет смысла загружать для неё более детальный мип, чем мип размером 10х10.

кстати, если ты не в курсе, все мипмапы вместе взятые для текстуры произвольного размера занимают примерно столько же памяти, сколько занимает 36% (вроде) её нулевого мипа. fun fact: для трёхмерных текстур эта величина ещё меньше, что-то порядка 15%.

поэтому высокие мипы занимают нисколько памяти и их можно просто всегда держать в памяти. а вот низкие мипы можно подгружать по необходимости.

#10
12:03, 25 фев. 2021

В GL ты не можешь вызвать апикол из другого потока. Либо делай атласы, массивы текстур, мегатекстуры из виртуальной памяти.

#11
12:11, 25 фев. 2021

lookid
> В GL ты не можешь вызвать апикол из другого потока.
Зато там есть расшареные контексты и загрузить текстуру со второго потока можно, совершая свои апиколы для каждого потока, но над одним ресурсом.
Другое дело, что если текстура большая, то пока она заливается она может занять шину или еще-что то и основной поток будет неприятно спайкать.

#12
13:06, 25 фев. 2021

Всё уже сделано. Посмотри такие игры как TES 3, 4, 5.

#13
13:10, 25 фев. 2021

Недавно делал условно асинхронную загрузку текстур для OpenGL. В DirectX апи мультипоточное, там все просто. С разными контекстами в OpenGL решил не морочить голову. Сделал так:
1. Текстуры грузятся и распаковываются в отдельном асинхронном (или нескольких) потоке.
2. А биндятся по требованию, когда движку уже нужен id прибинденной текстуры.
Неожиданно все получилось хорошо. Никаких "рывков" по бинду в момент запросу текстуры не заметил. Видимо, узкое место не шина, а диск и распаковка.

#14
14:12, 25 фев. 2021

HolyDel
> Зато там есть расшареные контексты и загрузить текстуру со второго потока
> можно, совершая свои апиколы для каждого потока, но над одним ресурсом.
Нестабильная это штука.
Мне больше нравится вариант, когда поток читает из файла тайлы и скидывает в поток с контекстом OpenGL, а тот уже загружает текстуры на ГПУ.
Т.е. вся работа с OpenGL не выходит за рамки одного потока.

Страницы: 1 2 3 Следующая »
ПрограммированиеФорумГрафика