В настоящее время есть 4 способа сделать это: стандартные 1D текстуры, текстуры буферов, однородные буферы и буферы хранения шейдеров.
1D текстуры
При использовании этого метода вы используете glTex(Sub)Image1D
, чтобы заполнить одномерную текстуру своими данными. Поскольку ваши данные - это просто массив с плавающей точкой, ваш формат изображения должен быть GL_R32F
. Затем вы получаете доступ к нему в шейдере с помощью простого вызова texelFetch
. texelFetch
принимает координаты текселя (отсюда и название) и отключает всю фильтрацию. Таким образом, вы получите ровно один тексель.
Примечание: texelFetch
- 3,0+. Если вы хотите использовать предыдущие версии GL, вам нужно будет передать размер шейдеру и нормализовать координату текстуры вручную.
Основными преимуществами здесь являются совместимость и компактность. Это будет работать на оборудовании GL 2.1 (с использованием нотации). И у вас нет для использования GL_R32F
форматов; Вы можете использовать GL_R16F
half-float. Или GL_R8
, если ваши данные соответствуют нормированному байту. Размер может много значить для общей производительности.
Основным недостатком является ограничение размера. Вы ограничены наличием 1D текстуры с максимальным размером текстуры. На оборудовании класса GL 3.x это будет около 8192, но гарантированно будет не менее 4096.
Объекты однородного буфера
Это работает так, что вы объявляете единообразный блок в своем шейдере:
layout(std140) uniform MyBlock
{
float myDataArray[size];
};
Затем вы получаете доступ к этим данным в шейдере, как массив.
Вернувшись в код на C / C ++ / etc, вы создаете буферный объект и заполняете его данными с плавающей точкой. Затем вы можете связать этот буферный объект с единообразным блоком MyBlock
. Более подробную информацию можно найти здесь.
Принципиальными преимуществами этой техники являются скорость и семантика. Скорость объясняется тем, как реализации обрабатывают однородные буферы по сравнению с текстурами. Выборки текстур - это глобальные обращения к памяти. Равномерный доступ к буферу обычно отсутствует; данные унифицированного буфера обычно загружаются в шейдер, когда шейдер инициализируется после его использования при рендеринге. Оттуда это локальный доступ, который намного быстрее.
Семантически, это лучше, потому что это не просто плоский массив. Для ваших конкретных потребностей, если все, что вам нужно, это float[]
, это не имеет значения. Но если у вас более сложная структура данных, семантика может быть важной. Например, рассмотрим массив источников света. Огни имеют позицию и цвет. Если вы используете текстуру, ваш код для определения положения и цвета для определенного источника света выглядит следующим образом:
vec4 position = texelFetch(myDataArray, 2*index);
vec4 color = texelFetch(myDataArray, 2*index + 1);
С унифицированными буферами это выглядит так же, как и любой другой универсальный доступ Вы назвали участников, которых можно назвать position
и color
. Таким образом, вся семантическая информация есть; легче понять, что происходит.
Для этого есть ограничения по размеру. OpenGL требует, чтобы реализации предоставляли как минимум 16 384 байта для максимального размера однородных блоков. Это означает, что для массивов с плавающей запятой вы получаете только 4096 элементов. Еще раз отметим, что это минимум , требуемый от реализаций; Некоторое оборудование может предложить гораздо большие буферы. Например, AMD предоставляет 65 536 на своем оборудовании класса DX10.
Буферные текстуры
Это своего рода "супер 1D текстура". Они эффективно позволяют получить доступ к объекту буфера из текстурного блока . Хотя они одномерные, они не являются одномерными текстурами.
Вы можете использовать их только с GL 3.0 или выше. И вы можете получить к ним доступ только через функцию texelFetch
.
Основным преимуществом здесь является размер. Буферные текстуры могут быть довольно гигантскими. Хотя спецификация в целом консервативна и требует не менее 65 536 байтов для буферных текстур, большинство реализаций GL позволяют им иметь размер мега байтов. Действительно, обычно максимальный размер ограничен доступной памятью графического процессора, а не аппаратными ограничениями.
Кроме того, буферные текстуры хранятся в буферных объектах, а не в более непрозрачных текстурных объектах, таких как 1D текстуры.Это означает, что вы можете использовать некоторые методы потоковой передачи буферных объектов для их обновления.
Основным недостатком здесь является производительность, как и в случае с 1D текстурами.Буферные текстуры, вероятно, не будут медленнее, чем 1D текстуры, но они не будут такими же быстрыми, как UBO.Если вы просто вытаскиваете из них один поплавок, это не должно вызывать беспокойства.Но если вы извлекаете из них много данных, рассмотрите возможность использования UBO.
Объекты буфера хранилища шейдеров
OpenGL 4.3 предоставляет другой способ справиться с этим: буферы хранилища шейдеров .Они очень похожи на однородные буферы;Вы определяете их, используя синтаксис, почти идентичный синтаксису единообразных блоков.Принципиальная разница в том, что вы можете написать им.Очевидно, что это бесполезно для ваших нужд, но есть и другие отличия.
Буферы хранения шейдеров, с концептуальной точки зрения, являются альтернативной формой текстуры буфера.Таким образом, ограничения по размеру для буферов хранения шейдеров на много больше, чем для однородных буферов.Минимум OpenGL для максимального размера UBO составляет 16 КБ.Минимальный OpenGL для максимального размера SSBO составляет 16MB .Так что, если у вас есть аппаратное обеспечение, это интересная альтернатива UBO.
Обязательно объявите их как readonly
, так как вы не пишете им.
Потенциальные возможностинедостаток здесь снова производительность по сравнению с UBO.SSBO работают как операция загрузки / сохранения изображения через буферные текстуры.По сути, это (очень хороший) синтаксический сахар для imageBuffer
типа изображения.Таким образом, чтение из них, вероятно, будет выполняться со скоростью чтения из readonly imageBuffer
.
. На данный момент неясно, является ли чтение через загрузку / сохранение изображения через буферные изображения быстрее или медленнее, чем текстуры буфера.
Другая потенциальная проблема заключается в том, что вы должны соблюдать правила для несинхронного доступа к памяти .Они сложны и могут очень легко сбить вас с толку.