Russian Qt Forum

Qt => 2D и 3D графика => Тема начата: UnSeen от Октябрь 05, 2011, 13:49



Название: Асинхронная загрузка текстур (OpenGL)
Отправлено: 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 не срабатывает :( Что я делаю не так? © :) Наверняка кто-то такое уже делал, ткните в пример, плиз


Название: Re: Асинхронная загрузка текстур (OpenGL)
Отправлено: Igors от Октябрь 05, 2011, 18:24
Сейчас занимаюсь тоже OpenGL текстурами, но "с др. стороны", поэтому пример не скину. Возможно полезно будет такое соображение:

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


Название: Re: Асинхронная загрузка текстур (OpenGL)
Отправлено: UnSeen от Октябрь 05, 2011, 18:45
Сейчас занимаюсь тоже OpenGL текстурами, но "с др. стороны", поэтому пример не скину. Возможно полезно будет такое соображение:

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

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


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


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


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


Название: Re: Асинхронная загрузка текстур (OpenGL)
Отправлено: UnSeen от Октябрь 05, 2011, 21:47
Заряжаю созданную текстуру в др. нитке - с какого перепугу это не должно работать? Конечно придется ответить/обеспечить что новое ID еще нигде  не используется - ну это нормально. Др. словами: нигде ясно не звучит что, мол, все действия в одной нитке игнорируются контекстом созданным в другой.

Проблема уже в "заряжаю" :) glBindTexture, вызванное из другого потока с тем же контекстом, выдаёт GL_INVALID_OPERATION . Так что увы, всё не так просто


Название: Re: Асинхронная загрузка текстур (OpenGL)
Отправлено: Igors от Октябрь 05, 2011, 22:28
Проблема уже в "заряжаю" :) glBindTexture, вызванное из другого потока с тем же контекстом, выдаёт GL_INVALID_OPERATION . Так что увы, всё не так просто
Ну привет, делать glBindTexture, (текущей) Вас в др. нитке никто не заставлял, речь шла о glTextImage.


Название: Re: Асинхронная загрузка текстур (OpenGL)
Отправлено: UnSeen от Октябрь 05, 2011, 22:59
И куда же вы будете загружать текстуру, если она не выбрана?

Нашёл, что я делал не так :)
Оказывается, создавать и связывать два контекста нужно в одном потоке. А потом уже можно использовать один из контекстов в другом потоке. А я пытался создавать контексты в разных потоках и это не срабатывало. Почему так - хз...
Теперь всё работает :)


Название: Re: Асинхронная загрузка текстур (OpenGL)
Отправлено: xop от Октябрь 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, при этом вместо указателя на данные там передается смещение относительно начала буфера

Если нужно подробнее - могу кусочки кода накидать.


Название: Re: Асинхронная загрузка текстур (OpenGL)
Отправлено: Igors от Октябрь 10, 2011, 11:18
xop, рад Вас видеть т.к. привалило много работы с OpenGL и нужны советы знатока.

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

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

Спасибо 


Название: Re: Асинхронная загрузка текстур (OpenGL)
Отправлено: xop от Октябрь 15, 2011, 17:18
Думаю лучше все-таки новую тему открыть. И заодно более подробно описать задачу, в которой понадобились разные текстурные координаты для разных текстур