Я собираюсь немного рассердиться на это, так как я действительно не понимаю, что не так, а что нет. Должно быть либо что-то, что я слишком неправильно понял, либо есть какая-то ошибка в коде или в драйвере. Я запускаю это на AMD Radeon 5850 с последними драйверами бета-версии драйверов на прошлой неделе.Чтение и обновление буфера текстур в OpenGL/GLSL 4.3
ОК, я начал выполнять реализацию рендеринга OIT и хотел использовать структурный массив, сохраненный в объекте буфера хранилища шейдеров. Ну, индексы в этом отражают/двигаются вперед по памяти неправильно, и я в значительной степени предполагал, что это ошибка драйвера - так как они совсем недавно начали поддерживать такую вещь + да, это бета-драйвер. Поэтому я переместился назад на метку и вместо этого использовал glsl-изображения из объектов текстурного буфера, которые, как я полагаю, поддерживались, по крайней мере, некоторое время назад.
Все еще не вел себя правильно. Поэтому я создал простой тестовый проект и немного пошарил, и теперь я думаю, что я просто ущипнул, где это все.
OK! Сначала я инициализирую буфер и текстуру.
//Clearcolor and Cleardepth setup, disabling of depth test, compile and link shaderprogram etc.
...
//
GLint tbo, tex;
datasize = resolution.x * resolution.y * 4 * sizeof(GLfloat);
glGenBuffers(1, &tbo);
glBindBuffer(GL_TEXTURE_BUFFER, tbo);
glBufferData(GL_TEXTURE_BUFFER, datasize, NULL, GL_DYNAMIC_COPY);
glBindBuffer(GL_TEXTURE_BUFFER, 0);
glGenTextures(1, &tex);
glBindTexture(GL_TEXTURE_BUFFER, tex);
glTexBuffer(GL_TEXTURE_BUFFER, GL_RGBA32F, tex);
glBindTexture(GL_TEXTURE_BUFFER, 0);
glBindImageTexture(2, tex, 0, GL_TRUE, 0, GL_READ_WRITE, GL_RGBA32F);
Затем цикл рендеринга - обновление и рисовать, обновление и рисовать ... С задержкой между так, что у меня есть время, чтобы увидеть, что делает обновление.
обновление, как это ...
ivec2 resolution; //Using GLM
resolution.x = (GLuint)(iResolution.x + .5f);
resolution.y = (GLuint)(iResolution.y + .5f);
glBindBuffer(GL_TEXTURE_BUFFER, tbo);
void *ptr = glMapBuffer(GL_TEXTURE_BUFFER, GL_WRITE_ONLY);
color *c = (color*)ptr; //color is a simple struct containing 4 GLfloats.
for (int i = 0; i < resolution.x*resolution.y; ++i)
{
c[i].r = c[i].g = c[i].b = c[i].a = 1.0f;
}
glUnmapBuffer(GL_TEXTURE_BUFFER); c = (color*)(ptr = NULL);
glBindBuffer(GL_TEXTURE_BUFFER, 0);
И рисовать, как это ...
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMemoryBarrier(GL_ALL_BARRIER_BITS);
ShaderProgram->Use(); //Simple shader program class
quad->Draw(GL_TRIANGLES); //Simple mesh class containing triangles (vertices) and colors
glFinish();
glMemoryBarrier(GL_ALL_BARRIER_BITS);
Я просто поставить некоторые барьеры памяти вокруг дополнительно убедиться , не должны вредить больше, чем производительность? Ну, результат был таким же с барьером или без него, так что ... :)
Программа Shader - это простой проходной шейдер вершин и шейдер фрагмента, который проводит тестирование.
Vertex шейдер
#version 430
in vec3 in_vertex;
void main(void)
{
gl_Position = vec4(in_vertex, 1.0);
}
Фрагмент шейдеры (я предполагаю, когерентное & MemoryBarrier() на самом деле не нужен здесь, так как я их на CPU между Жеребьевка/фрагмент исполнения шейдеров ... но это вред)
#version 430
uniform vec2 iResolution;
layout(binding = 2, rgba32f) coherent uniform imageBuffer colorMap;
out vec4 FragColor;
void main(void)
{
ivec2 res = ivec2(int(iResolution.x + 0.5), int(iResolution.y + 0.5));
ivec2 pos = ivec2(int(gl_FragCoord.x + 0.5), int(gl_FragCoord.y + 0.5));
int pixelpos = pos.y * res.x + pos.x;
memoryBarrier();
vec4 prevPixel = imageLoad(colorMap, pixelpos);
vec4 green = vec4(0.0, 1.0, 0.0, 0.0);
imageStore(colorMap, pixelpos, green);
FragColor = prevPixel;
}
Expectation: белый экран! Поскольку я пишу «белый» для всего буфера между каждой ничью, даже если я пишу зеленым изображение после загрузки в фактическом шейдере.
Результат: Первый кадр зеленый, остальные черные. Некоторая часть меня думает, что есть белая рамка, которая слишком быстро, чтобы ее можно было увидеть, или какая-то vsync-вещь, которая плести его, но это место для логики? : P
Ну, тогда я попробовал новую вещь и переместил блок обновления (где я пишу «белый» во весь буфер) вместо init.
Ожидание: белый первый кадр, за которым следует зеленый экран.
Результат: О да, зеленый цвет! Хотя первый кадр с некоторыми артефактами белого/зеленого, иногда только зеленого. Возможно, это связано с (отсутствием) vsync чего-то, не проверил это. Тем не менее, я думаю, что получил результат, который я искал.
Вывод, который я могу сделать из этого, заключается в том, что в моем обновлении что-то не так. Отбрасывает ли буфер из ссылки на текстуру или что-то в этом роде? В этом случае, не странно, что первый кадр в порядке? Только после первой команды imageStore (ну, в первом кадре) текстура становится черной - «bind() - map() - unmap() - bind (0)» работает в первый раз, но не после. Моя картинка glMapBuffer заключается в том, что она копирует данные буфера с графического процессора в память процессора, давайте изменим его и Unmap скопирует его обратно. Ну, теперь я подумал, что, возможно, он не копирует буфер с GPU на CPU, а затем обратно, но только один способ? Может ли быть GL_WRITE_ONLY, который должен быть изменен на GL_READ_WRITE? Ну, я попробовал оба. Предположительно, один из них был прав, не будет ли мой экран при использовании этого, который всегда будет белым в «тесте 1»?
ARGH, что я делаю неправильно?
EDIT: Ну, я до сих пор не знаю ... Очевидно glTexBuffer(GL_TEXTURE_BUFFER, GL_RGBA32F, tex);
должно быть glTexBuffer(GL_TEXTURE_BUFFER, GL_RGBA32F, tbo);
, но я думаю, что tbo
и tex
имел такое же значение, так как они были получены в том же порядке. Поэтому он работал в этой реализации. Я решил это, хотя, в некотором роде, я не очень доволен, так как я действительно думаю, что вышеприведенное должно работать. С другой стороны, новое решение, вероятно, немного лучше по производительности. Вместо того, чтобы использовать glMapBuffer()
, я переключился на сохранение копии ТВ-памяти на CPU с помощью glBufferSubData()
и glgetBufferSubData()
для отправки данных между CPU/GPU. Это сработало, поэтому я просто продолжу это решение.
Но, вопрос все еще стоит - Почему glMapBuffer()
не работает с моими объектами буфера текстуры?