Пользовательский распределитель для хранения вектора stl в объектах буфера OpenGL - PullRequest
1 голос
/ 14 января 2012

Я хочу настроить класс std::vector, чтобы использовать буферный объект OpenGL в качестве хранилища.

Возможно ли это сделать, не полагаясь на конкретную реализацию STL, написав собственный распределитель и / илисоздание подкласса контейнера?

Моя проблема заключается в том, как создать методы-оболочки для glMapBuffer / glUnmapBuffer, чтобы использовать буферный объект для рендеринга, который оставляет контейнер в согласованном состоянии.

Ответы [ 3 ]

2 голосов
/ 14 января 2012

Возможно ли это сделать, не полагаясь на конкретную реализацию STL, написав собственный распределитель и / или разделив контейнер на подклассы?

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

До C ++ 11 распределители не могут иметь состояние . Они не могут иметь полезных членов, потому что контейнеры не обязаны фактически использовать распределитель, который вы передаете. Им разрешено создавать свои. Таким образом, вы можете установить тип распределителя, но вы не можете назначить ему конкретный распределитель экземпляр и ожидать, что этот экземпляр будет всегда использоваться.

Таким образом, ваш распределитель не может просто создать буферный объект и сохранить его внутри. Это должно было бы использовать глобальный (или частный статический или любой другой) буфер. И даже тогда несколько экземпляров будут использовать один и тот же буфер.

Вы могли бы обойти это, если бы распределитель хранил (в частных статических переменных) ряд буферных объектов и сопоставленных указателей. Это позволит вам выделить объект буфера определенного размера, и вы получите отображенный указатель обратно. Диллокатор будет использовать указатель, чтобы выяснить, из какого объекта буфера он получен, и выполнить соответствующую очистку для него.

Конечно, это было бы совершенно бесполезным для того, чтобы что-то делать с этими буферами. Вы не можете использовать буфер, который в настоящее время отображается. И если ваш распределитель удаляет буфер, как только вектор завершен с памятью, вы никогда не сможете использовать этот буферный объект для выполнения чего-либо.

Кроме того, не забывайте: отключение буфера может привести к сбою по неизвестным причинам. Если произойдет сбой, вы не сможете узнать, что это произошло, потому что вызов unmap находится в распределителе. И деструкторы не должны бросать исключения.

C ++ 11 делает так, чтобы распределители могли иметь состояние. Это означает, что это более или менее возможно. Вы можете заставить распределитель пережить std::vector, который построил данные, и, следовательно, вы можете запросить распределитель для пост-сопоставления объекта буфера. Вы также можете хранить информацию о том, не удалось ли удалить карту.

Это все еще не делает это хорошей идеей. В целом, гораздо проще просто использовать обычный старый std::vector и использовать glBufferSubData для его загрузки. В конце концов, отображение буфера с помощью READ_WRITE почти гарантирует, что это будет обычная память, а не адрес GPU. Это означает, что при отображении просто будет выполняться DMA, что glBufferSubData делает. Вы не получите большую производительность при картировании.

Перераспределение с буферными объектами будет гораздо более болезненным. Поскольку объект std::vector определяет, какой объем дополнительной памяти хранить, вы не можете играть в такие игры, как выделение большого буферного объекта и последующее увеличение объема памяти, используемой контейнером. Каждый раз, когда std :: vector думает, что ему нужно больше памяти, вам нужно будет создать новое имя объекта буфера, а std :: Vector сделает поэлементную копию из отображенной памяти в отображенную память.

Не очень быстро.

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

2 голосов
/ 14 января 2012

Я хочу настроить класс std :: vector, чтобы использовать буферный объект OpenGL в качестве хранилища.

Хотя это, конечно, возможно, я настоятельно не рекомендую делать это. Отображенные буферные объекты должны быть не отображены, прежде чем они могут быть использованы OpenGL в качестве ввода данных. Таким образом, такой производный, назовем его glbuffervector, должен отображать / отменять отображение объекта буфера для каждого доступа. Кроме того, получение адреса разыменованного элемента не будет работать, поскольку после разыменования объект буфера снова не будет отображен.

Вместо того, чтобы пытаться создать вектор, который хранится в буферном объекте, я бы реализовал ссылочный контейнер, который может быть создан из существующего буферного объекта вместе с макетом, чтобы можно было получать итераторы. В соответствии со схемой RAII объект буфера будет отображен при создании экземпляра и не сопоставлен с освобождением экземпляра.

1 голос
/ 14 января 2012

Возможно ли это сделать, не полагаясь на конкретную реализацию STL, написав собственный распределитель и / или подклассы контейнер

Если вы используете Microsoft Visual C ++, есть запись в блоге, описывающая, как определить пользовательский распределитель STL: "The Mallocator" . Я думаю, что написание пользовательских распределителей зависит от реализации STL.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...