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