Chce przełączać się między danymi przekazanymi do ssbo, tak, aby odpowiednie polecenie rysowania miało odpowiednie uniformy. Wiem, że do tego potrzebuje użyć glBindBufferRange()
z odpowiednim parametrem offset. Przeczytałem, że offset musi być wielokrotnością GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT dla ubo, ale dla ssbo sytuacja może wyglądać inaczej, bo std430 naprawia niektóre rzeczy, z którymi std140 miał problem.
Ten pseudokod nie będzie zawierał vao, vbo, danych wierzchołka ani shadera wierzchołków, bo nie mają te rzeczy znaczenia w tym problemie.
Pierwsze czego spróbowałem to najprostszy sposób:
struct Color
{
float r, g, b, a;
};
struct V2
{
float x, y;
};
struct Uniform
{
Color c1;
Color c2;
V2 v2;
float r;
float f;
int t;
};
GLuint ssbo = 0;
std::vector<Uniform> uniform;
int main()
{
//create window, context etc.
glCreateBuffers(1, &ssbo);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo);
Uniform u;
u.c1 = {255, 0, 255, 255 };
u.c2 = {255, 0, 255, 255 };
u.v2 = { 0.0f, 0.0f };
u.r = 0.0f;
u.f = 100.0f;
u.t = 0;
uniform.push_back(u);
u.c1 = {255, 255, 0, 255 };
u.c2 = {255, 255, 0, 255 };
u.v2 = { 0.0f, 0.0f };
u.r = 100.0f;
u.f = 100.0f;
u.t = 1;
uniform.push_back(u);
u.c1 = {255, 0, 0, 255 };
u.c2 = {255, 0, 0, 255 };
u.v2 = { 0.0f, 0.0f };
u.r = 100.0f;
u.f = 0.0f;
u.t = 0;
uniform.push_back(u);
bool quit = false;
while(!quit) {
glNamedBufferData(ssbo, sizeof(Uniform) * uniform.size(), uniform.data(), GL_STREAM_DRAW);
for(int i = 0; i < uniform.size(); ++i) {
glBindBufferRange(GL_SHADER_STORAGE_BUFFER, 1, ssbo, sizeof(Uniform) * i, sizeof(Uniform));
glDrawArrays(...);
}
//swap buffer etc.
}
return 0;
}
mamy 3 uniformy, więc i 3 polecenia rysowania. Dla mojej wygody przyjmijmy, że rysujemy kwadraty.
fragment shader
#version 460 core
layout(location = 0) out vec4 f_color;
layout(std430, binding = 1) buffer Unif
{
vec4 c1;
vec4 c2;
vec2 v2;
float r;
float f;
int t;
};
void main()
{
f_color = vec4(t, 0, 0, 1);
}
W tym przykładzie dostaje błąd GL_INVALID_VALUE
glBindBufferRange()
, który na pewno pochodzi z argumentu offset
, ponieważ w następnych "implementacjach", ten błąd znika, ale za to pojawia się inny problem.
Przechodząc dalej, skoro to nie działa to pomyślałem, że może użyję GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT
i formuły, którą znalazłem w internecie
int align = 4;
glGetIntegerv(GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT, &align);
int ssboSize = sizeof(Uniform) + align - sizeof(Uniform) % align;
pokażę tylko zmienioną wersje glNamedBufferData()
i glBindBufferRange()
, bo tylko to się zmienia. Więc:
glNamedBufferData(ssbo, ssboSize * uniform.size(), uniform.data(), GL_STREAM_DRAW);
glBindBufferRange(GL_SHADER_STORAGE_BUFFER, 1, ssbo, ssboSize * i, sizeof(Uniform));
I ten sposób prawie zadziałał.
Z tego w jaki sposób ustawiłem zmienną Uniform::type
, czyli
uniform[0].type == 0
uniform[1].type == 1
uniform[2].type == 0
shader powinien narysować 3 kwadraty o w kolorach
pierwsze polecenie rysowania
vec4(0, 0, 0, 1);
drugie polecenie rysowania
vec4(1, 0, 0, 1);
trzecie polecenie rysowania
vec4(0, 0, 0, 1);
jednak kolory są pozamieniane kolejnością i jest o tak:
pierwsze polecenie rysowania
vec4(1, 0, 0, 1);
drugie polecenie rysowania
vec4(0, 0, 0, 1);
trzecie polecenie rysowania
vec4(0, 0, 0, 1);
Czy to jest na pewno problem z offsetem w makro glBindBufferRange()
, czy może tu chodzi o coś innego?
Co powinienem zmienić żeby poprawie używać ssbo?