#glMultiDrawArraysIndirect Draws One Instance

32 messages · Page 1 of 1 (latest)

kindred oriole
#

I've looked into the CPU side of the equation and everything is just fine. It draws the first instance in the buffer (which starts at the beginning of the buffer), but it refuses to do so for a second one.

For the record, this is my first time attempting to understand OpenGL.

#

In my constructor:

    glGenVertexArrays(1, &vao);
    glGenBuffers(1, &vbo);
    glGenBuffers(1, &IndirectBuffer);

    glBindVertexArray(vao);
    glBindBuffer(GL_ARRAY_BUFFER, vbo);
    glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), nullptr);
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)(16)); // I've neglected to wrap glVertexAttribPointer, so this is all manually done in the constructor, don't mind it
    glEnableVertexAttribArray(1);
    glVertexAttribDivisor(1, 1);
    glBindVertexArray(0);

In the draw method:

if (CommandBuffer.empty()) [[unlikely]]
    return;

glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, this->capacity(), this->data(), GL_DYNAMIC_DRAW);

glBindVertexArray(vao);

glBindBuffer(GL_DRAW_INDIRECT_BUFFER, IndirectBuffer);
glBufferData(GL_DRAW_INDIRECT_BUFFER,
    CommandBuffer.size() * sizeof(DrawArraysIndirectCommand),
    CommandBuffer.data(), GL_DYNAMIC_DRAW);

glMultiDrawArraysIndirect(GL_TRIANGLES, nullptr, static_cast<GLsizei>(CommandBuffer.size()), sizeof(DrawArraysIndirectCommand));

glBindVertexArray(0);

Vertex shader:

#version 430 core

layout(location = 0) in vec3 aPos;
layout(location = 1) in vec4 aColor;

out vec4 vertexColor;

void main()
{
    gl_Position = vec4(aPos, 1.0);
    vertexColor = aColor;
}

Fragment shader:

#version 430 core

in vec4 vertexColor;
out vec4 FragColor;

void main()
{
    FragColor = vertexColor;
}
#

CommandBuffer is a vector of

struct DrawArraysIndirectCommand {
    GLuint count;
    GLuint instanceCount;
    GLuint first;
    GLuint baseInstance;
};

and is set up per-instance as count: the amount of vertices, instanceCount: 1, first: the offset in the vector, baseInstance: same as first

Depth test is enabled, if that helps.

#

I'm missing something about instancing, and I'd very much appreciate any help.

modern swan
#

"in my constructor" red flag

#

also very strange that you're interleaving your vertex data and instance data

#

in any case, check renderdoc

glass terrace
#

Yeah renderdoc and make sure you have debug message callback installed to catch errors

glass terrace
#

Setting first and baseinstance feels a bit off. Wonder if one om should be 0?

kindred oriole
#

So, baseInstance should have been zero. first should have been represented in the amount of vertices instead of bytes.

modern swan
#

from the attributes you've described your buffer looks to be a tightly packed list of:

struct Vertex {
    vec4 pos;
    vec4 instanceData;
};

which forces you to either have the same number of instances as you have vertices, or to have a tonne of wasted space in your buffer

#
  • if you ever want to change the instance data, that's going to be a massive pain in the ass, because you have to somehow do that without touching the actual vertex data you want to instance
#

hopefully that answers your❓

kindred oriole
#

This runs on a custom allocator, so changing the amount of vertices is not an issue. Vertex is defined as (basically a __m128 Position, __m128 Color). Reading instances from the buffer at an offset is effectively the same as using pointers, and there is an actual conversion to a pointer that is possible, so it is, in effect, the same as using traditional dynamic allocation except it's.. customized, possibly more cache-local, etc.

modern swan
#

i don't really understand how any of that relates to what i said. my point is that your Vertex struct does not compose only a single vertex. storing instance data interleaved with vertex data is extremely unusual at best

#

you're not going to see better cache locality because for every instance you need to read every vertex anyway, and since everything is interleaved, you're only going to be able to fit half the actual vertex data in cache

#

even if you only have a single instance, you're still allocating space for as many instances as you have vertices

#

and like I said, changing that instance data is going to be awful. you're either going to need to spam glbuffersubdata or map and do a tonne of sparse writes, neither of which are great

#

it seems overly complicated for no reason

kindred oriole
#

Vertices being closer in memory should improve cache locality. I've only just begun hearing about cache locality, so if you could explain why I'm wrong, I would appreciate it.

If you mean instances, where the mesh is the set of vertices or some set of offsets ruled in the shader from a position/quaternion structure and the in-general data is somewhere else (like if the entire mesh should be a certain color retrieved by reference), then I agree under the scenario where I would want that. Everything is per-vertex because the vertex data is not supposed to be per-instance.

But, I don't know if I'm getting what exactly you're getting at.

#

For every vector of vertices added, the buffer would be updated once. In the draw method, glbufferdata is used when the size needs to change (the arena size changed) and glbuffersubdata when not.

I think. I'm currently not at my work station, so I don't remember what my final result was. I just remember trying to move onto textures and getting stuck because bindless textures sound great but I don't know how supported they actually are, and that alternatives kinda suck.

kindred oriole
modern swan
modern swan
kindred oriole
#

Actually, I recall changing the constructor to just generate the buffers. This is all a testing phase, and I fully understand why the constructor I sent here is bad.

kindred oriole
modern swan
#

i can not see what you have removed or added, i can only see what you have posted here and comment on that

#

and what you have posted here is incorrect

#

if you have fixed it already then great, but in that case we have absolutely nothing to comment on

kindred oriole
modern swan
#

that is not what I'm talking about