Разница между «буфером» и «массивом» в OpenGL?

12

Когда я читаю документацию по webGL или OpenGL, можно увидеть некоторые закономерности использования имен функций и объектов. Но я не могу понять разницу между буферным объектом и массивом.

Существуют «объекты буфера вершин», «объекты массива вершин» и даже какой-то «буферный массив» или «буфер массива».

В контексте OpenGL, когда что-то является «массивом» и когда оно должно называться «буфером»?

coobit
источник
Некоторые перспективы, подумайте о получении данных по сети и сохранении журнала всего полученного. Вам нужно прочитать сокет и поместить полученные данные куда-нибудь, чтобы вы могли передать их, это буфер. Часто это может быть локально ограниченный, динамически размещаемый простой тип списка. Иногда это так просто, как char* buffer = socketRead();(псевдокод). Журнал, с другой стороны, живет в течение всего жизненного цикла приложения. Таким образом, вы создаете массив где-то и начинаете читать сокет, каждый раз, когда вы получаете данные, которые записываете этот кусок в массив, давая вам аккуратный список всех полученных вами данных.
Кевин

Ответы:

5

Наименование объекта Vertex Array несколько неудачно. Есть три разные вещи, которые появляются (используются, чтобы появляться) в / с / вокруг вашего приложения, и которые (исторически) называются по-разному, с именем «массив» или «буфер» (ну, есть и объекты фреймбуфера, но я это проигнорирую).

  1. Данные, которые живут в вашем приложении, формально и фактически, но которые извлекаются OpenGL за один раз (в отличие от vertex-by-vertex). Когда-то это было то, что вы бы назвали массивом вершин .
    Цель этого состояла в том, чтобы сделать доступ более эффективным, так как OpenGL мог бы просто скопировать все это за один раз в четко определенное время, когда вы дали обещание, что данные согласованы, и переместить их через AGP или что-то еще в одном блоке. Это больше не существует.
  2. Данные скрыты и доступны с помощью дескриптора, который может быть «привязан», то есть сделан активным. Фактически данные могут фактически находиться в оперативной памяти или на видеокарте или перемещаться в область, совместимую с PCIe, как угодно, но в любом случае формально вы не владеете (даже если они физически находятся в ОЗУ и если данные поступили из вашего приложения) ) это - если вы в настоящее время не «сопоставили» его через соответствующий API, возвращая записываемый (и иногда читаемый) указатель. Вы также ограничены в своей способности контролировать то, что происходит с данными (вы можете дать некоторые подсказки, но это в значительной степени так).
    OpenGL может перемещать эти данные более или менее свободно, и вам разрешено / разрешено копировать в / из буфера только через соответствующий API или получать доступ к данным во время их отображения. Это то, что вы называете буферным объектом ( объект буфера вершин, если он содержит вершины, но на самом деле это не обязательно, это могут быть также данные изображения или униформа, только вершины, которые были поддержаны первыми, когда-то давно).
    Цель этого состоит в том, чтобы гарантировать, что OpenGL может (в принципе) делать то, что он хочет, он может даже спекулятивно увеличить буфер над PCIe, прежде чем вы начнете рисовать. Это работает, потому что вы не владеете данными (OpenGL делает!), И вы можете получить к ним доступ только через данный API, поэтому всегда известно, что данные действительны. Драйвер может даже отказаться от использования буферной памяти на видеокарте, когда ему требуется память для чего-то другого, а затем восстановить ее из секретной копии, когда это необходимо.
  3. Действительно глупый неправильный термин, для которого гораздо лучшим именем будет что-то вроде набора буферов или набора дескрипторов, это печально известный объект массива вершин . С вашей точки зрения, это не что иное, как набор буферных дескрипторов, сгруппированных под другим неясным дескриптором (который вы можете связать). Как это происходит, реальность немного сложнее. На самом деле, VAO намного ближе к тому, как работает само оборудование. Графические карты имеют небольшое количество (часто около 2, 4 или 8) наборов дескрипторов (не только для буферов, но и для сэмплеров) с очень многими записями в каждом, между которыми они могут очень эффективно переключаться ,
    Теперь цель объекта массива вершин состоит в том, чтобы уменьшить количество вызовов API и уменьшить количество проверок согласованности, которые OpenGL должен выполнить внутри, и, конечно, использовать аппаратное обеспечение как оно есть. Если вы связываете 5 буферов, то каждый должен пройти некоторые, возможно, дорогостоящие проверки, и каждый из них является кандидатом на отсутствие кеша в драйвере, плюс каждый требует обмена данными с графической картой для изменения дескриптора и т. Д. И т. Д. Если вы вместо этого привязав один VAO, драйвер может (часто) просто переключать дескриптор, установленный на видеокарте, и все готово.
Damon
источник
8

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

(вытащил из хроноса )

Каждый буфер имеет тенденцию составлять один атрибут массива вершин (объект). VAO может содержать много атрибутов вершин (например, положение, цвет, UV). Каждый из них может храниться в своем собственном буфере, где буфер указывает неформатированную последовательность смежных байтов, и где вам нужно явно указать размер (тип) для каждого элемента буфера как для вызовов OpenGL на стороне процессора, так и для работы шейдеров на стороне GPU.

Это один из способов. Другие способы это может работать:

  • Все атрибуты хранятся с чередованием в одном буфере, ИЛИ
  • Некоторые атрибуты существуют в своих собственных выделенных буферах, в то время как другие разделяют буферы.

Диаграмма ниже иллюстрирует эти два последних случая.

введите описание изображения здесь

Итог: если фраза «массив вершин» используется без определения в OpenGL, можно предположить, что это означает VAO, что в контексте OpenGL (в частности) действительно очень отличается от буфера.

РЕДАКТИРОВАТЬ ваш комментарий: GL_ARRAY_BUFFERуказывает на намерение использовать этот буферный объект для данных атрибута вершины, как описано выше. Это связано с тем, что буферы используются не только для атрибутов вершин. Однако, поскольку это наиболее распространенный вариант использования, и вы спрашиваете о VAO, я не буду вдаваться в другие; Здесь, однако, приведен список других типов буферов, которые можно настроить.

инженер
источник
Итак, буферы : 1. находятся в графическом процессоре, 2. большую часть времени содержат один тип данных (только вершина, только цвет и т. Д.), 3. данные чередуются, то есть 111122223333 и т. Д. 4. не предоставлять метод для доступа к данным (не в буфер [2] или в буфер [vertex_3434]). Теперь массивами являются: 1. набор буферов, 2. хранилище информации о том, как анализировать содержащиеся в нем буферы (то есть шаг хранения массива). , размер элемента, смещения, поэтому данные из буферов могут быть доступны правильно. правильно?
coobit
1. Буферы существуют на обоих концах и передаются между процессором и графическим процессором (возможно, обратно и вперед), иначе как бы вы заполнили данные для загрузки в графический процессор при загрузке меша с диска? Да, элементы имеют одинаковый тип по всему буферу, но в зависимости от технологии, которую вы используете, каждый элемент буфера может быть либо примитивом, либо structтипом. Данные могут чередоваться или быть полностью однородными для каждого буфера. Вы можете индексировать их так же, как с помощью традиционного массива C в ЦП. Массив объектов (используйте эту правильную терминологию или в конечном итоге запутываете себя!) ... (продолжение ниже)
Инженер,
2. Да, и вам нужно явно убедиться, что ваши объявления буфера в шейдере будут соответствовать тем спецификациям, которые вы установили в VAO на стороне ЦП: «Все состояния, связанные с определением данных, используемых процессором вершин, инкапсулированы в вершине объект массива. " (хронос документы)
Инженер
Итак, просто чтобы побить гвоздь больше ... Как люди работали до AO, используя только BO? Или АО всегда присутствовали в OpenGL, и это просто VAO, который был представлен позже, чем VBO?
coobit
@coobit io7m.com/documents/history-vertex-spec - это дает вам представление о различиях между фиксированным конвейером (старая школа) OpenGL, 3Dfx и т. д. и современным программируемым конвейером OpenGL и Direct3D.
инженер
5

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

Первая версия OpenGL не имела ни одного из этих типов объектов. Рисование было достигнуто с помощью нескольких вызовов glBegin / glEnd, и одной из проблем этой модели было то, что она была очень неэффективной с точки зрения затрат на вызов функции.

OpenGL 1.1 предпринял первые шаги для решения этой проблемы, представив массивы вершин. Вместо непосредственного указания данных вершин вы можете теперь получать их из массивов C / C ++ - отсюда и название. Таким образом, массив вершин - это всего лишь массив вершин и состояние GL, необходимое для их определения.

Следующая основная эволюция пришла с GL 1.5 и позволила хранить данные массива вершин в памяти графического процессора, а не в системной («клиентской») памяти. Слабым местом спецификации массива вершин GL 1.1 было то, что полный набор данных вершин должен был передаваться в GPU каждый раз, когда вы хотели его использовать; если он уже был на GPU, то такой передачи можно было бы избежать и добиться потенциального увеличения производительности.

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

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

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

Введите объект массива вершин, который собирает все это вместе.

Итак, подведем итог: массив вершин начал свою жизнь как набор состояний и данных (хранящихся в массиве) для рисования. Буфер вершин заменяет хранение массива в памяти с типом объекта GL, оставляя массив вершин просто быть состоянием. Объект массива вершин - это просто контейнерный объект для этого состояния, позволяющий изменять его проще и с меньшим количеством вызовов API.

Максимус Минимус
источник
0

Я не работал с OpenGL какое-то время, поэтому я могу быть только наполовину прав. Вообще говоря: буферы хранят массив неформатированной памяти. Массив является общим термином непрерывной памяти.

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

Надеюсь, что это помогает немного

Juicef
источник
Что такое GL_ARRAY_BUFFER тогда? Почему это так назвали? Согласно вашей гипотезе, это «Неформатированная непрерывная память» :)
coobit
Ну, этот конкретный пример - просто идентификатор буфера (с которым вы связываете свой массив). Буфер массива (в вашем примере) используется для атрибутов вершин, поэтому в основном вы связываете свой массив атрибутов вершин с буфером. Звучит странно, поэтому позвольте мне привести вам пример. У вас есть некоторый массив на стороне процессора, который может быть цветным, нормальным, позициями и т. Д., И теперь вы хотите, чтобы gpu получил к нему доступ. То есть, когда входит bindBuffer, он в основном отображает ваш "cpu-array" в "gpu-array".
Juicef
Что касается того, почему это назвали так, я не могу ответить на это. Я бы предположил, что это потому, что у вас есть массив различных данных, которые
входят