1
votes

I'm instancing an object in positions calculated in a compute shader. I want to bind the output of the compute shader containing the positions to the array buffer for drawing but I cant get it to work. I apologize about the index arithmetics, I got super paranoid about memory alignment and ditched all vectors.

Relevant code simplified:

Initialization:

//x, y, z, 1 stored in succession
/*float*/positions = new float[maxPositionCount * 4];

//initialize positions_vbo
glGenBuffers(1, &position_vbo);
glBindBuffer(GL_ARRAY_BUFFER, position_vbo);
glBindBuffer(GL_ARRAY_BUFFER, 0);

//initialize positionsOUT_ssbo
glGenBuffers(1, &positionsOUT_ssbo);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, positionsOUT_ssbo);
glBufferData(GL_SHADER_STORAGE_BUFFER, 4 * maxPositionCount * sizeof(float), NULL, GL_DYNAMIC_COPY);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 8, positionsOUT_ssbo);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);

//initialize positionCounter
glGenBuffers(1, &positionCount_acb);
glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, positionCount_acb);
glBufferData(GL_ATOMIC_COUNTER_BUFFER, sizeof(GLuint), NULL, GL_DYNAMIC_DRAW);
glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 7, positionCount_acb);
glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0);

Draw Loop:

//initialize the counter
posCount = 0;
glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 7, positionCount_acb);
glBufferSubData(GL_ATOMIC_COUNTER_BUFFER, 0, sizeof(GLuint),  &posCount);

//send other data to compute shader in order to calculate positions
//dispatch and wait
//....

//retrieve the counter
glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 7, positionCount_acb);
glGetBufferSubData(GL_ATOMIC_COUNTER_BUFFER, 0, sizeof(GLuint), &positionCount_acb);

//retrieve the positions (1)
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 8, positionsOUT_ssbo);
glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, posCount * 4 * sizeof(float), positions);

//bind position_vbo  (2)
glBindBuffer(GL_ARRAY_BUFFER, position_vbo);
glBufferData(GL_ARRAY_BUFFER, 4 * sizeof(float) * posCount, posCount > 0 ? &positions[0] : NULL, GL_DYNAMIC_DRAW);
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, 4 * sizeof(float), 0);
glVertexAttribDivisor(2, 1);

//instead of (1)+(2) I would like to know if something like this is possible
//glBindBuffer(GL_ARRAY_BUFFER, positionsOUT_ssbo);
//glEnableVertexAttribArray(2);
//glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, 4 * sizeof(float), 0);
//glVertexAttribDivisor(2, 1);

//bind vertex array and draw the object instances
glBindVertexArray(vertexArrayOfTheObjectImDrawing);
glDrawElementsInstanced(GL_TRIANGLES, objectSharedVertexCount, GL_UNSIGNED_SHORT, 0, posCount);

compute shader:

layout(local_size_x = 8, local_size_y = 8, local_size_z = 8) in;

//just in case they are relevant somehow
//can set and get them fine but they have fixed size (maxPositionCount)
//---------v
layout(std430, binding=4) buffer A {
    int a[ ];
};
layout(std430, binding=5) buffer B {
    int b[ ];
};
layout(std430, binding=6) buffer C {
    int c1,c2,c3,c4,c5;
};
//----------^

layout(binding = 7, offset = 0) uniform atomic_uint returnedPositionsIndex;

layout(std430, binding=8) buffer pos_Out
{
    float positionsOUT[ ];
};

void main()
{
    ivec3 currentPos = gl_GlobalInvocationID.xyz;

    if (I_want_that_position_returned(currentPos))
    {
        uint i = atomicCounterIncrement(returnedPositionsIndex);
        positionsOUT[i * 4 + 0] = float(index3D.x);
        positionsOUT[i * 4 + 1] = float(index3D.y);
        positionsOUT[i * 4 + 2] = float(index3D.z);
        positionsOUT[i * 4 + 3] = 1.0;
    }
}

vertex shader:

uniform mat4 worldViewProjection;
layout(location = 1) in vec4 vertPosition;
layout(location = 2) in vec4 position;
int main() {
     gl_Position = worldViewProjection * (vertPosition + position);
}

Currrentlly it crashes on the

glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, posCount * 4 * sizeof(float),  positions);

call, even if its the only uncommented line on the program. Debug error:

Exception thrown at 0x0000000001A132A9 (atio6axx.dll) in asd.exe:
0xC0000005: Access violation writing location 0x0000000000000000.

I have tried initializing the data by calling glBufferData(...positions) beforehand. The atomic counter is retrieved with the correct count. Also, is there a way to send the position data from the positionsOUT_ssbo without copying and binding to positions_vbo?

EDIT: Crash fixed, redeclared variable "positions" when initializing..

EDIT2: The lines I commented above is indeed a way to "bind" an ssbo's contents straight to the array buffer. If there's a better way, please feel free to share.

1
Well that was embarassing. I redeclared the class variable positions in the initializing phase, shadowing the one in the draw loop. Works fine now. Thanks for pointing me in the right direction! Funny thing is I only did that when minimizing the code to test for errors, and the cause for not working in the first place got fixed along the way. Anyway, I'll leave this open for the second part of the question since there's has to be a better way to achieve what I'm trying to do.potis
I've removed my comment and added it as a response because you've indicated it solved your problem. If you still need help in addition to the issue that just got resolved, then I'd recommend you ask a separate question instead of trying to add more questions to the original post. Please consider up-voting and accepting my answer. It benefits both of us, and the community at large. This is also how we say 'thank you' around here :)code_dredd
I know, no1 stack overflow lurker right here :). Although I would like some insight on the second part, I doubt this warrants a repost.potis
Since your question is not explicitly divided into parts, I'm not sure it's clear what you consider the "2nd part" to be. It's also not clear to me what you're trying to accomplish by "binding" outputs back to an array buffer, if that made sense. I think a repost of the specific issue at hand might be warranted (i.e. reduced scope), but that's just my opinion. My experience is mostly on the graphics pipeline, not compute shaders specifically, but are you asking about transform feedback? Also, not sure I see a reason to ditch the vectors, but responding there might be too "opinion-based".code_dredd
No reason at all I was just trying to eliminate all possible culprits for this not working, and I was getting desperate. I now changed them back to glm::vec4. About "binding" to the array buffer, maybe my terminology is incorrect, but surely you can see the advantage of not having to copy to RAM and upload back to the GPU since you already have it there. I actually got it working and it's the exact same lines I commented above. I see a decent fps gain for more than 10 million instances.potis

1 Answers

0
votes

Well that was embarassing. I redeclared the class variable positions in the initializing phase, shadowing the one in the draw loop. Works fine now. Thanks for pointing me in the right direction!

Based on your comment, I've reproduced my original comment below as the response.


I see that you have float* positions = new float[maxPositionCount * 4]; but I never see when values are actually added into this array, so it's an uninitialized memory block as far as I can tell.

You then call glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, posCount * 4 * sizeof(float), positions); which appears to send this uninitialized memory block, which may be set to zero, and would explain why you're getting the Access violation writing location 0x0000000000000000. error.