Главная Статьи Ссылки Скачать Скриншоты Юмор Почитать Tools Проекты Обо мне Гостевая Форум |
Вершинные буфера (VBO, vertex buffer object) являются удобным механизмом хранения, передачи и обновления данных на GPU. Для вершинных буферов имеется возможность отображения содержимого буфера в адресное пространство приложения, позволяющая заполнять вершинный буфер данными и/или изменять содержимое существующего вершинного буфера.
Однако возможность изменять содержимое существующего вершинного буфера несет в себе и потенциальную ловушку - мы можем попробовать изменить содержимое буфера, который либо уже используется, либо будет использован предшествующими командами OpenGL. В этом случае OpenGL должен либо заблокировать запрос на изменение буфера до тех пор, пока не станет безопасным его изменение, либо создать копию буфера.
Оба этих подхода не эффективны и желательно дать программисту больший контроль за синхронизацией содержимого буфера на GPU и изменениями, совершаемые на клиентской части (CPU). Рассматриваемые в данной статье расширения как раз предназначены для более эффективного решения данной проблемы.
Данное расширение (вошедшее в OpenGL 3.0) позволяет как явно задать область буфера, к которой будет осуществляться доступ, так и задать характер доступа, включая возможность полностью асинхронного доступа, когда приложение само отвечает за синхронизацию данных. Оно основано на расширении APPLE_flush_buffer_range.
Расширение вводит функцию glMapBufferRange, позволяющую отображать в адресное пространство приложения заданную область вершинного буфера, задавая при этом требуемый вид доступа.
void * glMapBufferRange ( GLenum target, GLintptr offset, GLsizeptr length, GLbitfield access );
Параметр target задает тип буфера и может принимать одно из следующих значений - GL_ARRAY_BUFFER, GL_ELEMENT_ARRAY_BUFFER, GL_PIXEL_UNPACK_BUFFER, GL_PIXEL_PACK_BUFFER, GL_TEXTURE_BUFFER и GL_UNIFORM_BUFFER.
Параметры offset и length задают диапазон буфера, который будет отображен в адресное пространство приложения. Параметр access является набором битов, описывающих требуемое отображение, все допустимые биты перечислены в следующей таблице.
Таблица 1. Биты, задающие тип доступа.
Название | Комментарий |
---|---|
GL_MAP_READ_BIT | Возвращаемый указатель будет предназначен только для чтения из буфера |
GL_MAP_WRITE_BIT | Возвращаемый указатель будет предназначен только для записи в буфер |
GL_MAP_INVALIDATE_RANGE_BIT | Предыдущие данные во всем отображенным диапазоне будут отброшены и должны быть полностью обновлены приложением. Данный флаг не может быть использован вместе с GL_MAP_READ_BIT. |
GL_MAP_INVALIDATE_BUFFER_BIT | Все предыдущие данные буфера будут отброшены и полностью перезаписаны приложением. Данный флаг не может быть использован вместе с GL_MAP_READ_BIT. |
GL_MAP_FLUSH_EXPLICIT_BIT | Все изменения буфера будут явно синхронизироваться при помощи вызова функции glFlushMappedBufferRange. Данный флаг может быть использован только вместе с GL_MAP_WRITE_BIT. |
GL_MAP_UNSYNCHRONIZED_BIT | OpenGL не должен пытаться синхронизировать операции с буфером, поданные до возвращения из glMapBufferRange. Данный флаг не может быть использован вместе с GL_MAP_READ_BIT. |
Для явной синхронизации измененных областей буфера используется следующая команда:
void glFlushMappedBufferRange ( GLenum target, GLintptr offset, GLsizeptr length );
Вызов данной функции приводит к явной синхронизации указанного диапазона (отсчитываемого от начала отображенного фрагмента буфера) между CPU и GPU.
На следующем примере весь буфер отображается для записи без синхронизации. OpenGL не будет ожидать завершения ранее поданных команд, поэтому приложение само отвечает за синхронизацию.
void * ptr = glMapBufferRange ( GL_ARRAY_BUFFER, 0, size, GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT );
Целью данного расширения (вошедшего в состав OpenGL 3.1) является предоставление возможности быстрого копирования содержимого одного вершинного буфера в другой вершинный буфер. В частности подобная функциональность может быть очень полезной при использовании отдельной нити для загрузки данных.
Данное расширение вводит два новых типа буферов (точнее точек привязки буферов - binding target)- GL_COPY_READ_BUFFER и GL_COPY_WRITE_BUFFER - специально для копирования буферов, чтобы не изменять привязку существующих буферов. Также данное расширение вводит специальную функцию glCopyBufferSubData для копирования содержимого одного буфера в другой.
void glCopyBufferSubData ( GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeptr size );
Данная функция служит для копирования заданного блока данных из одного вершинного буфера в заданное положение другого вершинного буфера. Сами буфера при этом идентифицируются при помощи точки привязки (binding target) - readTarget и writeTarget. В качестве значений для этих параметров могут выступать - GL_ARRAY_BUFFER, GL_ELEMENT_ARRAY_BUFFER, GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, GL_PIXEL_PACK_BUFFER, GL_PIXEL_UNPACK_BUFFER, GL_TEXTURE_BUFFER, GL_TRANSORM_FEEDBACK_BUFFER и GL_UNIFORM_BUFFER.
Параметры readOffset и writeOffset определяют смещения, начиная с которых осуществляется копирование данных, а параметр size задавал количество байт, которые необходимо скопировать из одного буфера в другой.
Данное расширение позволяет создать временный буфер (возможно на другой ните), заполнить его данными, а затем просто одной командой, практически не загружающей CPU, скопировать эти данные в другой буфер. Ниже приводится простой пример использования данного расширения.
GLuint tempBuffer;
// create temporary buffer
glGenBuffers ( 1, &tempBuffer );
glBindBuffer ( GL_COPY_READ_BUFFER, tempBuffer );
glBufferData ( GL_COPY_READ_BUFFER, size, NULL, GL_STREAM_DRAW );
// map this buffer into client's address space
void * ptr = glMapBuffer ( GL_COPY_READ_BUFFER, GL_WRITE_ONLY );
// fill buffer with data
. . . .
glUnmapBuffer ( GL_COPY_BUFFER );
// now quickly copy it to workBuffer
glBindBuffer ( GL_COPY_WRITE_BUFFER, workBuffer );
glCopyBufferSubData ( GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, 0, size );