Расширения ARB_map_buffer_range и ARB_copy_buffer

Вершинные буфера (VBO, vertex buffer object) являются удобным механизмом хранения, передачи и обновления данных на GPU. Для вершинных буферов имеется возможность отображения содержимого буфера в адресное пространство приложения, позволяющая заполнять вершинный буфер данными и/или изменять содержимое существующего вершинного буфера.

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

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

Расширение ARB_map_buffer_range

Данное расширение (вошедшее в 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 );

Расширение ARB_copy_buffer

Целью данного расширения (вошедшего в состав 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 );

Используются технологии uCoz