Главная Статьи Ссылки Скачать Скриншоты Юмор Почитать Tools Проекты Обо мне Гостевая |
Данное расширение (драйверы от NVidia поддерживают его начиная с release 55) расширяет возможности вершинных буферов (VBO, Vertex Buffer Object), вводимых расширением ARB_vertex_buffer_object.
Вводимые им вершинные буфера являются ни чем иным как набором (массивом) байтов и могут выступать в качестве источника данных для многих команд OpenGL.
Расширение EXT_pixel_buffer_object добавляет два новых типа (target) вершинных буферов - GL_PIXEL_PACK_BUFFER_EXT и GL_PIXEL_UNPACK_BUFFER_EXT.
Рассмотрим их оба по отдельности.
Если создать VBO этого типа (смотря пример кода ниже), то команды glReadPixels и glGetTexImage* будут читать данные пикселов прямо в соответствующий вершинный массив. При этом передаваемый в команду адрес трактуется как смещение внутри вершинного массива.
// создать вершинный буфер для numVertices вершин, каждая из которых // состоит из 4 float-ов unsigned vertexBuffer; glGenBuffers ( 1, vertexBuffer ); glBindBuffer ( GL_PIXEL_PACK_BUFFER_EXT, vertexBuffer ); glBufferData ( GL_PIXEL_PACK_BUFFER_EXT, numVertices*4, NULL, GL_DYNAMIC_DRAW ); // осуществить рендеринг в BACK-буфер glDrawBuffer ( GL_BACK ); renderVertexData (); // прочесть данные в вершинный буфер glReadBuffer ( GL_BACK ); glReadPixels ( 0, 0, numVertices*4, height/2, GL_BGRA, GL_FLOAT, 0 ); // назначить вершинный буфер как источник вершин // и осуществить рендеринг геометрии, определяемой этим массивом glBindBuffer ( GL_ARRAY_BUFFER, vertexBuffer ); glEnableClientState( GL_VERTEX_ARRAY); glVertexPointer ( 4, FLOAT, 0, 0 ); glDrawArrays ( GL_TRIANGLE_STRIP, 0, numVertices);
Приведенный выше пример осуществляет рендеринг в фреймбуфер (возможно с использованием вершинных и/или фрагментных программ), а затем читает оттуда пикселы в вершинный массив как набор четырехмерных вещественных векторов (float4).
После этого данный вершинный буфер используется для рендеринга, задаваемых им точек как triangle strip.
Тем самым данный тип VBO фактически позволяет реализовать так называемый рендеринг в вершинный буфер, т.е. позволяет использовать результаты рендеринга (набор пикселов) как набор геометрических данных для вершинного массива.
Так использование этой возможности позволяет быстро строить изменяющиеся на каждом шаге вершинные массивы очень большого размера не перегружая при этом ни CPU, ни вершинный конвейер GPU.
Если создать VBO данного типа, то команды glDrawPixels, glBitmap, glCompressedTexImage, glTexImage и glTexSubImage будут брать данные пикселов из соответствующего вершинного массива. Переданный в команду указатель как и ранее трактуется просто как смещение внутри буфера.
Одним из применений VBO данного типа является осуществление асинхронных запросов типа glReadPixels.
Дело в том, что если требуется прочесть и обработать сразу несколько изображений, то при использовании обычного подхода управление не будет возвращено из glReadPixels пока не будет передан последний байт запрашиваемых данных.
Т.е. все операции должны выполняться последовательно одна за другой.
За счет использования вершинных буферов этот процесс можно распараллелить - каждый из запросов glReadPixels, читающий в вершинный массив, немедленно возвращает управление. За счет этого можно не только параллельно запустить несколько операций чтения, но и даже начать обработку переданных данных.
// создать вершинные буфера необходимого размера unsigned imageBuffers [2]; glGenBuffers ( 2, imageBuffers ); glBindBuffer ( GL_PIXEL_PACK_BUFFER_EXT, imageBuffers [0] ); glBufferData ( GLPIXEL_PACK_BUFFER_EXT, imageSize / 2, NULL, GL_STATIC_READ ); glBindBuffer ( GL_PIXEL_PACK_BUFFER_EXT, imageBuffers [1] ); glBufferData ( GL_PIXEL_PACK_BUFFER_EXT, imageSize / 2, NULL, GL_STATIC_READ ); // осуществить рендеринг glDrawBuffer ( GL_BACK ); renderScene (); // Начать две асинхронные операции чтения // Каждая из них вернет управление сразу же glBindBuffer ( GL_PIXEL_PACK_BUFFER_EXT, imageBuffers [0] ); glReadPixels ( 0, 0, width, height/2, GL_BGRA, GL_UNSIGNED_BYTE, 0 ); glBindBuffer ( GL_PIXEL_PACK_BUFFER_EXT, imageBuffers [1] ); glReadPixels ( 0, height/2, width, height/2, GL_BGRA, GL_UNSIGNED_BYTE, 0 ); // Обработать частичные изображения pboMemory1 = glMapBuffer ( GL_PIXEL_PACK_BUFFER_EXT, GL_READ_ONLY ); processImage(pboMemory1); pboMemory2 = glMapBuffer ( GL_PIXEL_PACK_BUFFER_EXT, GL_READ_ONLY ); processImage(pboMemory2); // отключить отображение буферов в память glBindBuffer ( GL_PIXEL_PACK_BUFFER_EXT, imageBuffers [0] ); glUnmapBuffer ( GL_PIXEL_PACK_BUFFER_EXT ); glBindBuffer ( GL_PIXEL_PACK_BUFFER_EXT, imageBuffers [1] ); glUnmapBuffer ( GL_PIXEL_PACK_BUFFER_EXT );
Еще одним применением этого типа VBO является загрузка текстур. Дело в том, что при загрузке текстуры из файла (или создании ее CPU), обычно выделяется некоторый блок памяти CPU, в который распаковывается из файла (создается) образ текстуры, и затем этот блок передается для загрузки в память GPU.
Можно избежать выделения этого блока в памяти CPU, если использовать вершинный буфер. Для этого строится его отображение в память (командой glMapBuffer), возвращающее просто указатель в память.
После этого чтение (создание) текстуры осуществляется уже по этому "отображенному" адресу. По окончании чтения текстуры отображение закрывается и данный вершинный буфер используется в качестве источника данных для команды glTexImage.
void * pboMemory, * texData; unsigned texBuffer; // create and bind texture image buffer object glGenBuffers ( 1, &texBuffer ); glBindBuffer ( GL_PIXEL_UNPACK_BUFFER_EXT, texBuffer ); glBufferData ( GL_PIXEL_UNPACK_BUFFER_EXT, texSize, NULL, GL_STREAM_DRAW ); texData = getNextImage (); while ( texData != NULL ) { // map the texture image buffer pboMemory = glMapBuffer ( GL_PIXEL_UNPACK_BUFFER_EXT, GL_WRITE_ONLY ); // modify (sub-)buffer data memcpy ( pboMemory, texData, texsize ); // unmap the texture image buffer glUnmapBuffer ( GL_PIXEL_UNPACK_BUFFER_EXT ); // update (sub-)teximage from texture image buffer glTexSubImage2D ( GL_TEXTURE_2D, 0, 0, 0, texWidth, texHeight, GL_BGRA, GL_UNSIGNED_BYTE, 0 ); // draw textured geometry glBegin ( GL_QUADS ); ... glEnd(); texData = getNextImage (); } glBindBuffer ( GL_PIXEL_UNPACK_BUFFER_EXT, 0 );
Более подробное описание работы с вершинными буферами (VBO) можно найти или на этом сайте по ссылке в начале статьи или в книге Расширения OpenGL.
О практическом применении данного расширения для рендеринга в вершинный буфер вы можете прочесть в статье Рендеринг в вершинный буфер (render-to-vertex-buffer) в OpenGL.