Russian Qt Forum
Сентябрь 30, 2024, 22:20 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1]   Вниз
  Печать  
Автор Тема: Асинхронная загрузка текстур (OpenGL)  (Прочитано 9772 раз)
UnSeen
Гость
« : Октябрь 05, 2011, 13:49 »

Задача в следующем - в приложении требуется подгружать текстуры в отдельном потоке, чтобы не затормаживать рисование в основном потоке (программа - аналог Google Earth, т.е. огромное количество текстур, но одновременно показывается только небольшая часть)
Нашёл такой же вопрос тут, но без ответа http://www.prog.org.ru/topic_1564_0.html

Как это делать в теории - понятно, но будет здорово, если кто-нибудь скинет рабочий пример.

Обычно это делается так: во втором потоке создаётся отдельный контекст рендеринга (т.к. нельзя использовать один в двух потоках одновременно) и они объединяются функцией wglShareLists. После чего текстуры, созданные во втором потоке, становятся доступны и в первом.
Вот именно с wglShareLists и проблема - контексты почему-то не хотят объединяться, функиция возвращает false Грустный Текстуры во втором потоке создаются, но в первом они, само собой, не доступны.

В первом потоке используется QGLWidget, поставленный в качестве viewport-а на QGraphicsScene
Во втором для создания контекста используется QGLPixelBuffer (так как, насколько я понимаю, создать окно вне основного потока нельзя? если что, с Qt работаю впервые)). При создании QGLPixelBuffer в качестве формата указываю GLWidget->format(), чтобы форматы были одинаковые у обоих контекстов. Но wglShareLists не срабатывает Грустный Что я делаю не так? © Улыбающийся Наверняка кто-то такое уже делал, ткните в пример, плиз
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #1 : Октябрь 05, 2011, 18:24 »

Сейчас занимаюсь тоже OpenGL текстурами, но "с др. стороны", поэтому пример не скину. Возможно полезно будет такое соображение:

Сама "загрузка текстуры для OpenGL" производится ф-цией glTexImage2D или аналогичной - в той обертке что Вы пользуете это выглядит как bindTexture метод. После выполнения этой операции исходный имедж не нужен, OpenGL скопировал его куда надо. Поэтому есть смысл все дела OpenGL делать в одной нитке, а "узкое место" (подгрузка имеджей с диска) вынести в отдельную нитку.
Записан
UnSeen
Гость
« Ответ #2 : Октябрь 05, 2011, 18:45 »

Сейчас занимаюсь тоже OpenGL текстурами, но "с др. стороны", поэтому пример не скину. Возможно полезно будет такое соображение:

Сама "загрузка текстуры для OpenGL" производится ф-цией glTexImage2D или аналогичной - в той обертке что Вы пользуете это выглядит как bindTexture метод. После выполнения этой операции исходный имедж не нужен, OpenGL скопировал его куда надо. Поэтому есть смысл все дела OpenGL делать в одной нитке, а "узкое место" (подгрузка имеджей с диска) вынести в отдельную нитку.

Я сначала тоже собирался этим ограничиться, но оказалось, что время загрузки и раскодирования с диска jpg текстуры сравнимо со временем закачки текстуры в видеопамять (даже если без создания мипмапов). Как-никак текстурка 1024х1024 - это 4 метра данных. Так что этот способ не идеальный, часть глюков останется, и это будет заметно из-за специфики программы: при перемещении карты приходится одновременно подгружать большое количество текстур, которые раньше были не видны.
Так что хотелось бы полностью вынести загрузку во второй поток. Чтобы всё честно, красиво и без извращений Улыбающийся
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #3 : Октябрь 05, 2011, 19:23 »

Я сначала тоже собирался этим ограничиться, но оказалось, что время загрузки и раскодирования с диска jpg текстуры сравнимо со временем закачки текстуры в видеопамять (даже если без создания мипмапов). Как-никак текстурка 1024х1024 - это 4 метра данных. Так что этот способ не идеальный, часть глюков останется, и это будет заметно из-за специфики программы: при перемещении карты приходится одновременно подгружать большое количество текстур, которые раньше были не видны.
У меня немного похожая задача, текстуры побольше (часто 8x8k), зато легче с drag'ом - я могу (и должен) загрузить все до того как началась интерактивщина. Зачем зачем Вы связались с разделяемым контекстом и.т..п ? Ну делайте glTextImage (затратную работу) во вспомогательной нитке (нужно синхронизировать только создание нового ID текстуры), не вижу почему это должно не работать.
Записан
UnSeen
Гость
« Ответ #4 : Октябрь 05, 2011, 19:45 »

У меня немного похожая задача, текстуры побольше (часто 8x8k), зато легче с drag'ом - я могу (и должен) загрузить все до того как началась интерактивщина. Зачем зачем Вы связались с разделяемым контекстом и.т..п ? Ну делайте glTextImage (затратную работу) во вспомогательной нитке (нужно синхронизировать только создание нового ID текстуры), не вижу почему это должно не работать.
Тем не менее, не работает Улыбающийся Нельзя одновременно использовать один и тот же контекст в двух потоках (что вполне объяснимо. как вы себе представляете, например, параллельное выполнение блоков glBegin-glEnd в разных потоках с одним контекстом?))))
wglShareLists, похоже, самое удобное и простое решение
http://www.gamedev.ru/code/forum/?id=72099
« Последнее редактирование: Октябрь 05, 2011, 19:47 от UnSeen » Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #5 : Октябрь 05, 2011, 20:28 »

Тем не менее, не работает Улыбающийся Нельзя одновременно использовать один и тот же контекст в двух потоках (что вполне объяснимо. как вы себе представляете, например, параллельное выполнение блоков glBegin-glEnd в разных потоках с одним контекстом?))))
wglShareLists, похоже, самое удобное и простое решение
http://www.gamedev.ru/code/forum/?id=72099
Ссылка интересная. Но я бы проверился прежде чем лезть в дебри с контекстами, тем более это несложно. Создаю текстуру с новым ID в главной нитке, glGenTextures быстрая операция. Заряжаю созданную текстуру в др. нитке - с какого перепугу это не должно работать? Конечно придется ответить/обеспечить что новое ID еще нигде  не используется - ну это нормально. Др. словами: нигде ясно не звучит что, мол, все действия в одной нитке игнорируются контекстом созданным в другой.
Записан
UnSeen
Гость
« Ответ #6 : Октябрь 05, 2011, 21:47 »

Заряжаю созданную текстуру в др. нитке - с какого перепугу это не должно работать? Конечно придется ответить/обеспечить что новое ID еще нигде  не используется - ну это нормально. Др. словами: нигде ясно не звучит что, мол, все действия в одной нитке игнорируются контекстом созданным в другой.

Проблема уже в "заряжаю" Улыбающийся glBindTexture, вызванное из другого потока с тем же контекстом, выдаёт GL_INVALID_OPERATION . Так что увы, всё не так просто
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #7 : Октябрь 05, 2011, 22:28 »

Проблема уже в "заряжаю" Улыбающийся glBindTexture, вызванное из другого потока с тем же контекстом, выдаёт GL_INVALID_OPERATION . Так что увы, всё не так просто
Ну привет, делать glBindTexture, (текущей) Вас в др. нитке никто не заставлял, речь шла о glTextImage.
Записан
UnSeen
Гость
« Ответ #8 : Октябрь 05, 2011, 22:59 »

И куда же вы будете загружать текстуру, если она не выбрана?

Нашёл, что я делал не так Улыбающийся
Оказывается, создавать и связывать два контекста нужно в одном потоке. А потом уже можно использовать один из контекстов в другом потоке. А я пытался создавать контексты в разных потоках и это не срабатывало. Почему так - хз...
Теперь всё работает Улыбающийся
Записан
xop
Гость
« Ответ #9 : Октябрь 10, 2011, 08:23 »

Делаю примерно так:
1) контекст только один, в основном потоке
2) выделяю заранее буфер для загрузки типа GL_PIXEL_UNPACK_BUFFER, с usage GL_STREAM_DRAW
3) когда надо грузить текстуру в основном потоке делаю glMapBuffer, полученный указатель на область памяти передаю в параллельный поток
4) в параллельном потоке загружаю текстуру в полученную область памяти и кидаю сообщение основному потоку
5) в основном потоке делаю glUnmapBuffer, и потом с этим буфером привязанным к target GL_PIXEL_UNPACK_BUFFER выполняю нужные glTexImage2D, при этом вместо указателя на данные там передается смещение относительно начала буфера

Если нужно подробнее - могу кусочки кода накидать.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #10 : Октябрь 10, 2011, 11:18 »

xop, рад Вас видеть т.к. привалило много работы с OpenGL и нужны советы знатока.

Общая задача поддерживать 2 и более текстур на 1 объекте со всеми типами и наворотами маппинга. (изначально приложение обходилось 1 текстурой). Сделал так: создаю UV координаты для каждой текстуры и затем использую glTextImage2D и glTetCoordPointer. Это работает, но возникает капитальнейший геморрой: UV seam (шов). Приходится "распиливать" полигоны по шву, с 2 и более текстурами это особенно неприятно.

Есть ли лучшее ("модерновое") решение?
Примечание: если лучше вынести это в отдельный топик - нет проблем

Спасибо 
Записан
xop
Гость
« Ответ #11 : Октябрь 15, 2011, 17:18 »

Думаю лучше все-таки новую тему открыть. И заодно более подробно описать задачу, в которой понадобились разные текстурные координаты для разных текстур
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.053 секунд. Запросов: 22.