|
Главная
Статьи
Ссылки
Скачать
Скриншоты
Юмор
Почитать
Tools
Проекты
Обо мне
Гостевая
|
С самого начала программируемые GPU работали исключительно с вещественными числами (32-bit float) - для этого достаточно взглянуть в спецификации расширений ARB_vertex_program и ARB_fragment_program.
Хотя в языке GLSL и есть поддержка типов bool и int, но фактически эти типы реализовывались через тип float, что в частности выражалось в отсутствии поддержки побитовых операций (для которых нет floating point аналогов).
Однако начиная с GPU Nvidia GeForce 8xxx появилась наконец полноценная поддержка целочисленных типов данных. При этом эта поддержка осуществляется как на уровне шейдеров, так и на уровне текстур - добавлены новые форматы текстур с целочисленными компонентами.
Эта поддержка опирается на два расширения OpenGL - EXT_texture_integer и EXT_gpu_shader4.
Первое расширение (EXT_texture_integer) вводит понятие "ненормализованных" целых. Дело в том, что OpenGL ранее использовал целые числа для ряда целей (например, представления цветов), но при этом эти числа считались представлением вещественных чисел из отрезка [0,1] и приводились к нему - т.е. эти числа при требовали нормализации и в исходном виде были недоступны (так обычно все компоненты текстуры представлены в виде 8-битовых беззнаковых значений, однако как для OpenGL, так и для шейдеров эти компоненты передаются уже как нормализованные вещественные числа).
Понятие ненормализованных чисел означает, что никакого преобразования их не происходит и они передаются как были заданы (т.е. при чтении из соответствующей текстуры шейдер получит именно целочисленное значение, записанное в текстуру).
Также расширение EXT_texture_integer вводит целый ряд форматов текстур с ненормализованными целочисленными знаковыми и беззнаковыми компонентами и различным количеством бит на компоненту (8/16/32).
Таблица 1. Целочисленные форматы текстур, вводимые расширением EXT_texture_integer.
| Формат | Число компонент | Число бит на компоненту | Знаковая/беззнаковая |
|---|---|---|---|
| GL_ALPHA8I_EXT | 1 | 8 | знаковая |
| GL_ALPHA8UI_EXT | 1 | 8 | беззнаковая |
| GL_ALPHA16I_EXT | 1 | 16 | знаковая |
| GL_ALPHA16UI_EXT | 1 | 16 | беззнаковая |
| GL_ALPHA32I_EXT | 1 | 32 | знаковая |
| GL_ALPHA32UI_EXT | 1 | 32 | беззнаковая |
| GL_LUMINANCE_ALPHA8I_EXT | 2 | 8 | знаковая |
| GL_LUMINANCE_ALPHA8UI_EXT | 2 | 8 | беззнаковая |
| GL_LUMINANCE_ALPHA16I_EXT | 2 | 16 | знаковая |
| GL_LUMINANCE_ALPHA16UI_EXT | 2 | 16 | беззнаковая |
| GL_LUMINANCE_ALPHA32I_EXT | 2 | 32 | знаковая |
| GL_LUMINANCE_ALPHA32UI_EXT | 2 | 32 | беззнаковая |
| GL_RGB8I_EXT | 3 | 8 | знаковая |
| GL_RGB8UI_EXT | 3 | 8 | беззнаковая |
| GL_RGB16I_EXT | 3 | 16 | знаковая |
| GL_RGB16UI_EXT | 3 | 16 | беззнаковая |
| GL_RGB32I_EXT | 3 | 32 | знаковая |
| GL_RGB32UI_EXT | 3 | 32 | беззнаковая |
| GL_RGBA8I_EXT | 4 | 8 | знаковая |
| GL_RGBA8UI_EXT | 4 | 8 | беззнаковая |
| GL_RGBA16I_EXT | 4 | 16 | знаковая |
| GL_RGBA16UI_EXT | 4 | 16 | беззнаковая |
| GL_RGBA32I_EXT | 4 | 32 | знаковая |
| GL_RGBA32UI_EXT | 4 | 32 | беззнаковая |
Кроме того, данное расширение вводит несколько новых функций, наиболее важными из которых являются следующие две:
void glClearColorIiEXT ( GLint r, GLint g, GLint b, GLint a ); void glClearColorIuiEXT ( GLuint r, GLuint g, GLuint b, GLuint a );
Данные функции служат для задание целочисленного (знакового и беззнакового) RGBA-значения, используемого для очистки фреймбуфера.
Расширение EXT_gpu_shader4 вводит необходимую поддержку целых чисел в шейдеры на GLSL.
Помимо уже имеющихся типов данных добавлены новые типы для беззнаковых целых - unsigned int, uvec2, uvec3 и uvec4.
Для всех целочисленных форматов введена полная поддержка всех побитовых операций, включая битовые сдвиги.
Для доступа к текстурам с целочисленными форматами ведены новые типы сэмплеров - isampler1D, isampler2D, isampler3D, isamplerCube, isampler2DRect, isampler1DArray, isampler2DArray, isamplerBuffer, usampler1D, usampler2D, usampler3D, usamplerCube, usampler2DRect, usampler1DArray, usampler2DArray и usamplerBuffer.
Для чтения из таких текстур используются стандартные функции доступа к текстурам (такие как texture2D, texture2DRect и т.п.), только с соответствующим типом сэмплера. Обратите внимание, что результаты чтения из целочисленных текстур также являются целочисленными (знакового или беззнакового типа в зависимости от типа сэмплера), т.е. тип возвращаемого значения зависит от типа сэмплера.
Также расширение вводит целочисленные вершинные атрибуты и целочисленные uniform и varying переменные. Для доступа к ним введены следующие новые функции:
void glVertexAttribI1iEXT ( GLuint index, GLint x ); void glVertexAttribI1uiEXT ( GLuint index, GLuint x ); void glVertexAttribI2iEXT ( GLuint index, GLint x, GLint y ); void glVertexAttribI2uiEXT ( GLuint index, GLuint x, GLuint y ); void glVertexAttribI3iEXT ( GLuint index, GLint x, GLint y, GLint z ); void glVertexAttribI3uiEXT ( GLuint index, GLuint x, GLuint y, GLuint z ); void glVertexAttribI4iEXT ( GLuint index, GLint x, GLint y, GLint z, GLint w ); void glVertexAttribI4uiEXT ( GLuint index, GLuint x, GLuint y, GLuint z, GLuint w ); void glVertexI4ivEXT ( GLuint inrex, const GLint * ptr ); void glVertexI4uivEXT ( GLuint inrex, const GLuint * ptr ); void glVertexAttribIPointerEXT ( GLenum index, int size, GLenum type, GLsizei stride, const void * ptr ); void glUniform1uiEXT ( GLint loc, GLuint x ); void glUniform2uiEXT ( GLint loc, GLuint x, GLuint y ); void glUniform3uiEXT ( GLint loc, GLuint x, GLuint y, GLuint z ); void glUniform4uiEXT ( GLint loc, GLuint x, GLuint y, GLuint z,GLuint z );
Еще одно важное изменение - у фрагментного шейдера появился новый способ возвращения значения - для этой цели можно использовать переменные, объявленные как varying out. Именно этот способ следует использовать при рендеринге в текстуру с целочисленными компонентами ( использовать gl_Color и gl_FragData нельзя , так как они floating point).
Расширение EXT_gpu_shader4 вводит некоторые ограничения - нельзя читать из текстур с целочисленными компонентами во floating point переменные, точно так же нельзя использовать для записи в целочисленный фреймбуфер floating point переменные. Поэтому основной способ для записи в такой фреймбуфер - это использовать ivec4 varying out переменные.
Ниже приводится пример простейшего фрагментного шейдера, осуществляющего чтение из целочисленной текстуры и запись в целочисленный фреймбуфер.
#extension GL_EXT_gpu_shader4 : enable // turn off warning
uniform isampler2DRect srcMap;
varying out ivec4 result;
void main ()
{
ivec4 tex = texture2DRect ( srcMap, gl_TexCoord [0].xy );
tex += ivec4 ( 1 );
result = ivec4 ( tex.x ^ tex.y, tex.x & tex.y, tex.x | tex.y, 777 );
}
Данный шейдер читает знаковое целочисленное значение из входной текстуры и возвращает результат применение нескольких побитовых операций над прочтенными значениями.
Обратите внимание на директиву #extension в начале шейдер - она сообщает компилятору о требуемом расширение и выключает выдачу предупредительных сообщений в лог компиляции.
Для связывания имени выходной переменной во фрагментном шейдере с определенным буфером используется двухшаговый процесс - сначала имя связывается с номером цветового канала при помощи функции glBindFragDataLocationEXT, а потом этому номеру сопоставляется соответствующий буфер при помощи команды glDrawBuffers. Ниже приводится описание команды glBindFragDataLocationEXT.
void glBindFragDataLocationEXT ( GLuint program, GLuint colorNumber, const char * name );
Далее приводится исходный текст на С++ простой программы, создающей одну целочисленную текстуру, заполняющую ее данными, а потом использующей шейдер для вывода сразу в два целочисленных фреймбуфера.
#include "libExt.h"
#include <glut.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include "libTexture.h"
#include "Vector3D.h"
#include "Vector4D.h"
#include "Framebuffer.h"
#include "GlslProgram.h"
#include "utils.h"
unsigned srcMap;
GLenum format = GL_RGBA32UI_EXT;
FrameBuffer buffer ( 512, 512, 0 );
GlslProgram program;
void display ()
{
glClear ( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
glutSwapBuffers ();
}
void reshape ( int w, int h )
{
glViewport ( 0, 0, (GLsizei)w, (GLsizei)h );
startOrtho ( w, h );
}
void key ( unsigned char key, int x, int y )
{
if ( key == 27 || key == 'q' || key == 'Q' ) // quit requested
exit ( 0 );
}
int main ( int argc, char * argv [] )
{
// initialize glut
glutInit ( &argc, argv );
glutInitDisplayMode ( GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH | GLUT_STENCIL );
glutInitWindowSize ( 512, 512 );
// create window
glutCreateWindow ( "OpenGL integer textures demo" );
// register handlers
glutDisplayFunc ( display );
glutReshapeFunc ( reshape );
init ();
initExtensions ();
assertExtensionsSupported ( "GL_EXT_texture_integer GL_EXT_framebuffer_object GL_EXT_gpu_shader4" );
unsigned screenMap1 = buffer.createColorRectTexture ( GL_RGBA_INTEGER_EXT, format );
unsigned screenMap2 = buffer.createColorRectTexture ( GL_RGBA_INTEGER_EXT, format );
buffer.create ();
buffer.bind ();
if ( !buffer.attachColorTexture ( GL_TEXTURE_RECTANGLE_ARB, screenMap1, 0 ) )
printf ( "buffer error with color attachment\n");
if ( !buffer.attachColorTexture ( GL_TEXTURE_RECTANGLE_ARB, screenMap2, 1 ) )
printf ( "buffer error with color attachment\n");
if ( !buffer.isOk () )
printf ( "Error with framebuffer\n" );
buffer.unbind ();
if ( !program.loadShaders ( "vertex.vsh", "fragment-2.fsh" ) )
{
printf ( "Error loading shaders:\n%s\n", program.getLog ().c_str () );
return 3;
}
int * buf = new int [4*256*256];
int * ptr = buf;
for ( int i = 0; i < 256; i++ )
for ( int j = 0; j < 256; j++ )
{
*ptr++ = i;
*ptr++ = j;
*ptr++ = 0;
*ptr++ = 0;
}
glEnable ( GL_TEXTURE_RECTANGLE_ARB );
glGenTextures ( 1, &srcMap );
glPixelStorei ( GL_UNPACK_ALIGNMENT, 1 ); // set 1-byte alignment
glBindTexture ( GL_TEXTURE_RECTANGLE_ARB, srcMap );
glTexImage2D ( GL_TEXTURE_RECTANGLE_ARB, 0, format, 256, 256, 0, GL_RGBA_INTEGER_EXT, GL_UNSIGNED_INT, buf );
glTexParameteri ( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
glTexParameteri ( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
glTexParameteri ( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP );
glTexParameteri ( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP );
GLenum buffers [] = { GL_COLOR_ATTACHMENT0_EXT, GL_COLOR_ATTACHMENT1_EXT };
program.bindFragOut ( "result1", 0 );
program.bindFragOut ( "result2", 1 );
program.bind ();
program.setTexture ( "srcMap", 0 );
program.unbind ();
reshape ( buffer.getWidth (), buffer.getHeight () );
buffer.bind ();
glDrawBuffers ( 2, buffers );
program.bind ();
drawQuad ( 256, 256 );
program.unbind ();
buffer.unbind ();
memset ( buf, '\0', 4*256*245*sizeof (int) );
buffer.bind ();
glReadBuffer ( GL_COLOR_ATTACHMENT0_EXT );
glReadPixels ( 0, 0, 255, 256, GL_RGBA_INTEGER_EXT, GL_UNSIGNED_INT, buf );
glReadBuffer ( GL_COLOR_ATTACHMENT1_EXT );
glReadPixels ( 0, 0, 255, 256, GL_RGBA_INTEGER_EXT, GL_UNSIGNED_INT, buf );
buffer.unbind ();
return 0;
}
Соответствующие вершинный и фрагментный шейдеры приводится ниже.
void main(void)
{
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
gl_TexCoord [0] = gl_MultiTexCoord0;
}
#extension GL_EXT_gpu_shader4 : enable
uniform isampler2DRect srcMap;
varying out ivec4 result1;
varying out ivec4 result2;
void main ()
{
ivec4 tex = texture2DRect ( srcMap, gl_TexCoord [0].xy );
tex += ivec4 ( 1 );
result1 = ivec4 ( tex.x ^ tex.y, tex.x & tex.y, tex.x | tex.y, 777 );
result2 = ivec4 ( 1, 2, 3, 4 );
}
По этой ссылке можно скачать весь исходный код к этой статье,а также откомпилированные примеры для M$ Windows и Linux.
Обратите внимание, что для компиляции примера вам понадобится новые версии библиотек libExt и классов FrameBuffer и GlslProgram.