Drawing multiple instances group with one draw call

Hi!
I’ve a problem.
I’ve a set of tiles with one texture and another set of tiles with another texture, without instancing I can use bindless texturing and draw everything with one draw call only.

for (unsigned int i = 0; i < m_normals.size(); i++) {

                   if (m_normals[i].getAllVertices().getVertexCount() > 0) {
                        //std::cout<<"next frame draw normal"<<std::endl;
                        if (m_normals[i].getMaterial().getTexture() == nullptr) {
                            perPixelLinkedList2.setParameter("haveTexture", 0.f);
                        } else {
                            math::Matrix4f texMatrix = m_normals[i].getMaterial().getTexture()->getTextureMatrix();
                            //perPixelLinkedList2.setParameter("textureMatrix", texMatrix);
                            perPixelLinkedList2.setParameter("haveTexture", 1.f);
                        }
                        if (m_normals[i].getMaterial().getType() == Material::WATER) {
                            perPixelLinkedList2.setParameter("water", 1.0f);
                        } else {
                            perPixelLinkedList2.setParameter("water", 0.0f);
                        }
                        if (core::Application::app != nullptr) {
                            float time = core::Application::getTimeClk().getElapsedTime().asSeconds();
                            perPixelLinkedList2.setParameter("time", time);
                        }
                        unsigned int p = m_normals[i].getAllVertices().getPrimitiveType();
                        /*if (m_normals[i].getVertexArrays()[0]->getEntity()->getRootType() == "E_MONSTER") {
                                std::cout<<"tex coords : "<<(*m_normals[i].getVertexArrays()[0])[0].texCoords.x<<","<<(*m_normals[i].getVertexArrays()[0])[0].texCoords.y<<std::endl;
                            }*/
                        for (unsigned int j = 0; j < m_normals[i].getAllVertices().getVertexCount(); j++) {

                            vbBindlessTex[p].append(m_normals[i].getAllVertices()[j],(m_normals[i].getMaterial().getTexture() != nullptr) ? m_normals[i].getMaterial().getTexture()->getId() : 0);
                        }

                    }
                }
                currentStates.blendMode = sf::BlendNone;
                currentStates.shader = &perPixelLinkedList2;
                currentStates.texture = nullptr;
                for (unsigned int p = 0; p < Batcher::nbPrimitiveTypes; p++) {
                    if (vbBindlessTex[p].getVertexCount() > 0) {

                        vbBindlessTex[p].update();
                        frameBuffer.drawVertexBuffer(vbBindlessTex[p], currentStates);
                        vbBindlessTex[p].clear();
                    }
                }

I do batching to group all vertices of tiles 1 (instance1) and all vertices of tiles 2 (instance 2) into two vertex arrays and then I put every vertices of tiles1 and tiles2 in a vertex buffer with the right texture index and I draw everything with a single draw call!!!

The problem is where I want to use instanced rendering.
This’ll not work :

 for (unsigned int i = 0; i < Batcher::nbPrimitiveTypes; i++) {
                    vbBindlessTex[i].clear();
                }
                std::vector<TransformMatrix*> tm;
                for (unsigned int i = 0; i < m_instances.size(); i++) {
                    if (m_instances[i].getAllVertices().getVertexCount() > 0) {
                        if (m_instances[i].getMaterial().getType() == Material::WATER) {
                            perPixelLinkedList.setParameter("water", 1.0f);
                        } else {
                            perPixelLinkedList.setParameter("water", 0.0f);
                        }
                        if (core::Application::app != nullptr) {
                            float time = core::Application::getTimeClk().getElapsedTime().asSeconds();
                            perPixelLinkedList.setParameter("time", time);
                        }
                        matrices.clear();
                        tm = m_instances[i].getTransforms();
                        for (unsigned int j = 0; j < tm.size(); j++) {
                            tm[j]->update();
                            std::array<float, 16> matrix = tm[j]->getMatrix().transpose().toGlMatrix();
                            for (unsigned int n = 0; n < 16; n++) {
                                matrices.push_back(matrix[n]);
                            }
                        }
                        glCheck(glBindBuffer(GL_ARRAY_BUFFER, vboWorldMatrices));
                        glCheck(glBufferData(GL_ARRAY_BUFFER, matrices.size() * sizeof(float), &matrices[0], GL_DYNAMIC_DRAW));
                        glCheck(glBindBuffer(GL_ARRAY_BUFFER, 0));
                        if (m_instances[i].getVertexArrays().size() > 0) {
                            Entity* entity = m_instances[i].getVertexArrays()[0]->getEntity();
                            for (unsigned int j = 0; j < m_instances[i].getVertexArrays().size(); j++) {
                                if (entity == m_instances[i].getVertexArrays()[j]->getEntity()) {
                                    unsigned int p = m_instances[i].getVertexArrays()[j]->getPrimitiveType();
                                    for (unsigned int k = 0; k < m_instances[i].getVertexArrays()[j]->getVertexCount(); k++) {
                                        vbBindlessTex[p].append((*m_instances[i].getVertexArrays()[j])[k], (m_instances[i].getMaterial().getTexture() != nullptr) ? m_instances[i].getMaterial().getTexture()->getId() : 0);
                                    }
                                }
                            }
                        }
                        //std::cout<<"texture : "<<m_instances[i].getMaterial().getTexture()<<std::endl;
                        //std::cout<<"entity : "<<m_instances[i].getVertexArrays()[0]->getEntity()->getRootEntity()->getType()<<std::endl;
                        if (m_instances[i].getMaterial().getTexture() != nullptr) {



                            //std::cout<<"texture"<<std::endl;
                            math::Matrix4f texMatrix = m_instances[i].getMaterial().getTexture()->getTextureMatrix();
                            //perPixelLinkedList.setParameter("textureMatrix", texMatrix);
                            perPixelLinkedList.setParameter("haveTexture", 1.f);
                        } else {
                            //std::cout<<"no texture"<<std::endl;
                            perPixelLinkedList.setParameter("haveTexture", 0.f);
                        }
                    }
                }
                currentStates.blendMode = sf::BlendNone;
                currentStates.shader = &perPixelLinkedList;
                currentStates.texture = nullptr;
                for (unsigned int p = 0; p < Batcher::nbPrimitiveTypes; p++) {
                    if (vbBindlessTex[p].getVertexCount() > 0) {
                        vbBindlessTex[p].update();
                        frameBuffer.drawInstanced(vbBindlessTex[p], vbBindlessTex[p].getPrimitiveType(), 0, vbBindlessTex[p].getVertexCount(), tm.size(), currentStates, vboWorldMatrices);
                        vbBindlessTex[p].clear();
                    }
                }

Because I have to put every matrices and vertices of the first instances group and making a drawcall and then put every matrices and vertices of the second instances group and making a second draw call.

Isn’t there any way to make it with a single draw call ?

I mean put matrices and instances of the first and second group of instance and draw everything ?

So I pass an array of instance group1 vertices size and instance2 vertices size and an array of numInstances of instance1 and numInstances of instance2 to an opengl function.

Thank.

EDIT : I’ve seen glMultiDrawIndirect but this is for glDrawElements and glDrawBaseElementBaseInstanced and I really don’t know what glDrawBaseElementInstanced is compared to glDrawElementInstanced.

For future reference, since this is an OpenGL forum, you’ll be more likely to get help with your question/problem if when posting code, you actually post OpenGL calls, not your app’s wrappers for everything. With what you’ve posted, we can’t really tell what you’re doing. We can only guess.

For instance, there are only 3 genuine OpenGL API calls in the above, and they don’t reveal much:

        glCheck(glBindBuffer(GL_ARRAY_BUFFER, vboWorldMatrices));
        glCheck(glBufferData(GL_ARRAY_BUFFER, matrices.size() * sizeof(float), &matrices[0], GL_DYNAMIC_DRAW));
        glCheck(glBindBuffer(GL_ARRAY_BUFFER, 0));

So… we’re populating some buffer object with matrices. Ok, how are we actually dispatching this work? And what’s the shader doing with instancing? No idea. All we’ve got is these wrappers:

        frameBuffer.drawVertexBuffer(vbBindlessTex[p], currentStates);
...
        frameBuffer.drawInstanced(vbBindlessTex[p], vbBindlessTex[p].getPrimitiveType(), 0, vbBindlessTex[p].getVertexCount(), tm.size(), currentStates, vboWorldMatrices);

leaving us to guess.

Sure. You can collapse N glDrawArraysInstanced() or N glDrawElementsInstanced() draw calls into a single draw call with glMultiDrawArraysIndirect or glMultiDrawElementsIndirect(). Works great! I do it all the time.

You just want to concatenate your vertex attribute arrays into 1 buffer object, your element indices into 1 buffer, and your uniform data for each instance of each now-separate draw call into 1 buffer object. With these MDI (MultiDrawIndirect) draw calls, each of your previous individual draw calls become a subdraw in the MDI draw call, each defined by its own subdraw record contained in the GL_DRAW_INDIRECT_BUFFER buffer object.

I think you mean:

Yeah, you can read about how these work in the man pages or the wiki here if you want:

But if you use an MDI draw call, you can just forget about these oddballs. The MDI draw calls support all this if/when you need it, by what you specify in the subdraw record (e.g. DrawElementsIndirectCommand struct).

For instance,

  • if you don’t need instancing, set instanceCount to 1. If you do, set it to a value > 1.
  • If you want the 1st instance in an instanced subdraw to have an instance ID other than 0, set that in baseInstance.
  • If for a subdraw, you want to start pulling indices at some offset into the index buffer (you’re going to want to, to offset to this model’s index data), then set that offset in firstIndex.
  • If for a subdraw you want to add some offset to the fetched index values (you’re probably going to want to, to offset to this model’s vertex data), set that in baseVertex.

So if you just use MDI draw calls, you can just forget these oddball glDraw*() calls with BaseVertex and/or BaseInstance in them, because MDI supports all that. Moreover, with the MDI draw calls you can batch all those old draw calls together into a single MDI draw call.

Ok I’ve read this tutorial https://perso.univ-lyon1.fr/jean-claude.iehl/Public/educ/M1IMAGE/html/group__mdi.html and it says we can draw instanced and non instances objects with one draw call.

But how to send transform matrices to buffer ? Because for instanced rendering I need to use one matrix per instance but for non instancing one transform matrix per vertex.

And don’t we need to use glEnableVertexAttrib like this ?

 void RenderTarget::drawInstanced(VertexBuffer& vertexBuffer, enum sf::PrimitiveType type, unsigned int start, unsigned int nb, unsigned int nbInstances, RenderStates states, unsigned int vboMatrix1, unsigned int vboMatrix2) {
            if (vertexBuffer.getVertexCount() == 0) {
                return;
            }

            if (activate(true))
            {
                if (!m_cache.glStatesSet)
                    resetGLStates();
                // Apply the view
                if (m_cache.viewChanged)
                    applyCurrentView();

                if (states.blendMode != m_cache.lastBlendMode)
                    applyBlendMode(states.blendMode);

                // Apply the texture
                sf::Uint64 textureId = states.texture ? states.texture->getNativeHandle() : 0;
                if (textureId != m_cache.lastTextureId)
                    applyTexture(states.texture);
                // Apply the shader
                if (states.shader)
                    applyShader(states.shader);
                if (m_versionMajor > 3 || m_versionMajor == 3 && m_versionMinor >= 3)
                    glCheck(glBindVertexArray(m_vao));
                if (m_cache.lastVboBuffer != &vertexBuffer) {
                    if (m_versionMajor > 3 || m_versionMajor == 3 && m_versionMinor >= 3) {
                        glCheck(glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer.vboVertexBuffer));
                        glCheck(glEnableVertexAttribArray(0));
                        glCheck(glEnableVertexAttribArray(1));
                        glCheck(glEnableVertexAttribArray(2));
                        glCheck(glVertexAttribPointer(0, 3,GL_FLOAT,GL_FALSE,sizeof(Vertex), (GLvoid*) 0));
                        glCheck(glVertexAttribPointer(1, 4,GL_UNSIGNED_BYTE,GL_TRUE,sizeof(Vertex),(GLvoid*) 12));
                        glCheck(glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*) 16));
                        glCheck(glEnableVertexAttribArray(3));
                        glCheck(glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer.vboNormalBuffer));
                        glCheck(glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, sizeof(sf::Vector3f), (GLvoid*) 0));
                        glCheck(glDisableVertexAttribArray(0));
                        glCheck(glDisableVertexAttribArray(1));
                        glCheck(glDisableVertexAttribArray(2));
                        glCheck(glDisableVertexAttribArray(3));
                        glCheck(glBindBuffer(GL_ARRAY_BUFFER, 0));

                        /*va_list args;
                        va_start(args, n);
                        for (unsigned int i = 0; i < n; i++) {
                            unsigned int vboMatrices = va_arg(args, unsigned int);
                            for (unsigned int j = 0; j < 4; j++) {
                                glCheck(glEnableVertexAttribArray(i * 4 + j + 3));
                                glCheck(glBindBuffer(GL_ARRAY_BUFFER, vboMatrices));
                                glCheck(glVertexAttribPointer(i * 4 + j + 3, 4, GL_FLOAT, GL_FALSE, sizeof(math::Matrix4f),
                                                        (const GLvoid*)(sizeof(GLfloat) * i * 4)));
                                glCheck(glBindBuffer(GL_ARRAY_BUFFER, 0));
                                glCheck(glVertexAttribDivisor(i * 4 + j + 3, 1));
                                glCheck(glDisableVertexAttribArray(i * 4 + j + 3));
                            }
                        }
                        va_end(args);*/
                        if (vboMatrix1 != 0) {
                            for (unsigned int i = 0; i < 4; i++) {
                                glCheck(glEnableVertexAttribArray(i + 4));
                                glCheck(glBindBuffer(GL_ARRAY_BUFFER, vboMatrix1));
                                glCheck(glVertexAttribPointer(i + 4, 4, GL_FLOAT, GL_FALSE, sizeof(math::Matrix4f),
                                                        (const GLvoid*)(sizeof(GLfloat) * i * 4)));
                                glCheck(glBindBuffer(GL_ARRAY_BUFFER, 0));
                                glCheck(glVertexAttribDivisor(i + 4, 1));
                                glCheck(glDisableVertexAttribArray(i + 4));
                            }
                        }
                        if (vboMatrix2 != 0) {
                            for (unsigned int i = 0; i < 4; i++) {
                                glCheck(glEnableVertexAttribArray(i + 8));
                                glCheck(glBindBuffer(GL_ARRAY_BUFFER, vboMatrix2));
                                glCheck(glVertexAttribPointer(i + 8, 4, GL_FLOAT, GL_FALSE, sizeof(math::Matrix4f),
                                                        (const GLvoid*)(sizeof(GLfloat) * i * 4)));
                                glCheck(glBindBuffer(GL_ARRAY_BUFFER, 0));
                                glCheck(glVertexAttribDivisor(i + 8, 1));
                                glCheck(glDisableVertexAttribArray(i + 8));
                            }
                        }
                        glCheck(glEnableVertexAttribArray(12));
                        glCheck(glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer.vboTextureIndexesBuffer));
                        glCheck(glVertexAttribIPointer(12, 1, GL_UNSIGNED_INT, sizeof(GLuint), (GLvoid*) 0));
                        glCheck(glDisableVertexAttribArray(12));
                        glCheck(glBindBuffer(GL_ARRAY_BUFFER, 0));
                    }
                    m_cache.lastVboBuffer = &vertexBuffer;

                }
                if (m_versionMajor > 3 || m_versionMajor == 3 && m_versionMinor >= 3) {
                    glCheck(glEnableVertexAttribArray(0));
                    glCheck(glEnableVertexAttribArray(1));
                    glCheck(glEnableVertexAttribArray(2));
                    glCheck(glEnableVertexAttribArray(3));
                    if (vboMatrix1 != 0) {
                        for (unsigned int i = 0; i < 4 ; i++) {
                            glCheck(glEnableVertexAttribArray(4 + i));
                        }
                    }
                    if (vboMatrix2 != 0) {
                        for (unsigned int i = 0; i < 4 ; i++) {
                            glCheck(glEnableVertexAttribArray(8 + i));
                        }
                    }
                    glCheck(glEnableVertexAttribArray(12));
                    static const GLenum modes[] = {GL_POINTS, GL_LINES, GL_LINE_STRIP, GL_TRIANGLES,
                                                       GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN, GL_QUADS};
                    GLenum mode = modes[type];
                    glCheck(glBindFramebuffer(GL_FRAMEBUFFER, m_framebufferId));
                    glCheck(glDrawArraysInstanced(mode,start,nb,nbInstances));
                    glCheck(glDisableVertexAttribArray(0));
                    glCheck(glDisableVertexAttribArray(1));
                    glCheck(glDisableVertexAttribArray(2));
                    glCheck(glDisableVertexAttribArray(3));
                    if (vboMatrix1 != 0) {
                        for (unsigned int i = 0; i < 4 ; i++) {
                            glCheck(glDisableVertexAttribArray(4 + i));
                        }
                    }
                    if (vboMatrix2 != 0) {
                        for (unsigned int i = 0; i < 4 ; i++) {
                            glCheck(glDisableVertexAttribArray(8 + i));
                        }
                    }
                    glCheck(glDisableVertexAttribArray(12));
                    glCheck(glBindVertexArray(0));
                }
            }
            applyTexture(nullptr);
            applyShader(nullptr);
        } //////////////////////////////////////////////////////////

The problem is that the glVertexAttrib are not the sames for instanced rendering and non instanced rendering so how to use a single draw call for both ?

void RenderTarget::drawVertexBuffer(VertexBuffer& vertexBuffer, RenderStates states) {
            if (vertexBuffer.getVertexCount() == 0) {
                return;
            }

            if (activate(true))
            {

                if (!m_cache.glStatesSet)
                    resetGLStates();
                // Apply the view
                if (m_cache.viewChanged)
                    applyCurrentView();

                if (states.blendMode != m_cache.lastBlendMode)
                    applyBlendMode(states.blendMode);

                // Apply the texture
                sf::Uint64 textureId = states.texture ? states.texture->getNativeHandle() : 0;
                if (textureId != m_cache.lastTextureId)
                    applyTexture(states.texture);
                // Apply the shader
                if (states.shader)
                    applyShader(states.shader);
                if (m_versionMajor > 3 || m_versionMajor == 3 && m_versionMinor >= 3)
                    glCheck(glBindVertexArray(m_vao));
                if (m_cache.lastVboBuffer != &vertexBuffer) {
                    if (m_versionMajor > 3 || m_versionMajor == 3 && m_versionMinor >= 3) {
                        glCheck(glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer.vboVertexBuffer));
                        glCheck(glEnableVertexAttribArray(0));
                        glCheck(glEnableVertexAttribArray(1));
                        glCheck(glEnableVertexAttribArray(2));
                        glCheck(glVertexAttribPointer(0, 3,GL_FLOAT,GL_FALSE,sizeof(Vertex), (GLvoid*) 0));
                        glCheck(glVertexAttribPointer(1, 4,GL_UNSIGNED_BYTE,GL_TRUE,sizeof(Vertex),(GLvoid*) 12));
                        glCheck(glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*) 16));
                        glCheck(glEnableVertexAttribArray(3));
                        glCheck(glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer.vboNormalBuffer));
                        glCheck(glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, sizeof(sf::Vector3f), (GLvoid*) 0));
                        glCheck(glEnableVertexAttribArray(4));
                        //std::cout<<"vbo texture index buffer : "<<vertexBuffer.vboTextureIndexesBuffer<<std::endl;
                        glCheck(glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer.vboTextureIndexesBuffer));

                        glCheck(glVertexAttribIPointer(4, 1, GL_UNSIGNED_INT/*,GL_FALSE*/,sizeof(GLuint),(GLvoid*) 0));
                        glCheck(glDisableVertexAttribArray(0));
                        glCheck(glDisableVertexAttribArray(1));
                        glCheck(glDisableVertexAttribArray(2));
                        glCheck(glDisableVertexAttribArray(3));
                        glCheck(glDisableVertexAttribArray(4));

                        glCheck(glBindBuffer(GL_ARRAY_BUFFER, 0));
                    } else {
                        glCheck(glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer.vboVertexBuffer));
                        glCheck(glEnableClientState(GL_COLOR_ARRAY));
                        glCheck(glEnableClientState(GL_TEXTURE_COORD_ARRAY));
                        glCheck(glEnableClientState(GL_VERTEX_ARRAY));
                        glCheck(glVertexPointer(3, GL_FLOAT, sizeof(Vertex), (GLvoid*) 0 ));
                        glCheck(glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(Vertex), (GLvoid*) 12));
                        glCheck(glTexCoordPointer(2, GL_FLOAT, sizeof(Vertex),(GLvoid*) 16));
                        glCheck(glEnableClientState(GL_NORMAL_ARRAY));
                        glCheck(glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer.vboNormalBuffer));
                        glCheck(glNormalPointer(GL_FLOAT, sizeof(sf::Vector3f), (GLvoid*) 0));
                        glCheck(glDisableClientState(GL_COLOR_ARRAY));
                        glCheck(glDisableClientState(GL_TEXTURE_COORD_ARRAY));
                        glCheck(glDisableClientState(GL_VERTEX_ARRAY));
                        glCheck(glDisableClientState(GL_NORMAL_ARRAY));
                        glCheck(glBindBuffer(GL_ARRAY_BUFFER, 0));
                    }
                    m_cache.lastVboBuffer = &vertexBuffer;
                }
                if (m_versionMajor > 3 || m_versionMajor == 3 && m_versionMinor >= 3) {
                    glCheck(glEnableVertexAttribArray(0));
                    glCheck(glEnableVertexAttribArray(1));
                    glCheck(glEnableVertexAttribArray(2));
                    glCheck(glEnableVertexAttribArray(3));
                    glCheck(glEnableVertexAttribArray(4));
                } else {
                    glCheck(glEnableClientState(GL_COLOR_ARRAY));
                    glCheck(glEnableClientState(GL_TEXTURE_COORD_ARRAY));
                    glCheck(glEnableClientState(GL_VERTEX_ARRAY));
                    glCheck(glEnableClientState(GL_NORMAL_ARRAY));
                }

                // Find the OpenGL primitive type
                static const GLenum modes[] = {GL_POINTS, GL_LINES, GL_LINE_STRIP, GL_TRIANGLES,
                                                   GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN, GL_QUADS};
                GLenum mode = modes[vertexBuffer.getPrimitiveType()];
                if (vertexBuffer.m_indexes.size() > 0) {
                    glCheck(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vertexBuffer.vboIndexBuffer));
                    glCheck(glBindFramebuffer(GL_FRAMEBUFFER, m_framebufferId));
                    glCheck(glDrawElements(mode, vertexBuffer.m_indexes.size(), GL_UNSIGNED_INT, (GLvoid*) 0));
                    glCheck(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
                } else {
                    //std::cout<<"draw arrays"<<std::endl;
                    //std::cout<<"frame buffer id : "<<m_framebufferId<<std::endl;
                    glCheck(glBindFramebuffer(GL_FRAMEBUFFER, m_framebufferId));
                    glCheck(glDrawArrays(mode, 0, vertexBuffer.getVertexCount()));
                }
                if (m_versionMajor > 3 || m_versionMajor == 3 && m_versionMinor >= 3) {
                    glCheck(glDisableVertexAttribArray(0));
                    glCheck(glDisableVertexAttribArray(1));
                    glCheck(glDisableVertexAttribArray(2));
                    glCheck(glDisableVertexAttribArray(3));
                    glCheck(glDisableVertexAttribArray(4));
                    glCheck(glBindVertexArray(0));
                } else {
                    glCheck(glDisableClientState(GL_COLOR_ARRAY));
                    glCheck(glDisableClientState(GL_TEXTURE_COORD_ARRAY));
                    glCheck(glDisableClientState(GL_VERTEX_ARRAY));
                    glCheck(glDisableClientState(GL_NORMAL_ARRAY));
                }
            }
            applyTexture(nullptr);
            applyShader(nullptr);
        }

Thanks

That doesn’t make sense; how do you use “one transform matrix per vertex”? Do you mean “per mesh”?

As for the link, it explains how to get per mesh/instance data to the shader. They have to become array accesses. You use the instance and draw indices to fetch the values of interest from a UBO or (more likely) an SSBO.

Then you can’t use the same draw call. You should change how you’re accessing data so that they’re not different.

Ok I used one draw call for instanced objects (multiDrawArrays), one draw call for non instanced object, one draw call for instances and indexes. (multiDrawElements) and on draw call for non instanced with indexes and it works fine for me.

I don’t know how to use vertex attrib and how to arrange the datas to reduce drawcalls because for instanced objects I use a vertex attrib with divisor 1 and for non instanced I have to use 0 if I put one transform matrix per vertex into the buffer for non instanced objects. For non instanced objects I transform them with the cpu and I haven’t any transformations matrix as vertex attribs…

Oh. Well you “can” pull in per-instance data via instanced vertex attr arrays and glVertexAttribDivisor. But you could instead pull it into your shader by reading it in from an array in a UBO or SSBO, indexed by gl_BaseInstance + gl_InstanceID. Try that.

The latter definitely works just fine with MDI. I use this quite a bit. The former (instanced vertex attr arrays) might as well. I just haven’t actually tried it. But give it a shot!

UPDATE: Consulting the OpenGL 4.6 spec, it’s pretty definite. glMultiDraw*Indirect() definitely supports (instanced vertex attr arrays).

To take glMultiDrawElementsIndirect() for instance, it’s defined in terms of:

  • glDrawElementsIndirect

which is defined in terms of:

  • glDrawElementsInstancedBaseVertexBaseInstance()

which, like glDrawArraysInstancedBaseInstance() most definitely supports instanced arrays (i.e. attributes with a non-zero divisor).

For details, see mentions of the non-existent but used for illustration purposes mentions of: DrawElementsOneInstance and DrawArraysOneInstance used to define the behavior of the instanced draw calls.

So I need to pass matrices per instance or per vertex and create a big ssbo and get datas with gl_InstanceBase + gl_InstanceId.

You can. Or just continue pulling them in via an instanced vertex array (vertex attr divisor).

I tried to pass matrices to an ssbo because with vertex attrib divisor that doesn’t draw non instanced stuff but it doesn’t draw anything!

void PerPixelLinkedListRenderComponent::drawInstances() {
            for (unsigned int i = 0; i < Batcher::nbPrimitiveTypes; i++) {
                vbBindlessTex[i].clear();
            }

            std::array<std::vector<DrawArraysIndirectCommand>, Batcher::nbPrimitiveTypes> drawArraysIndirectCommands;
            std::array<std::vector<float>, Batcher::nbPrimitiveTypes> matrices;
            std::array<unsigned int, Batcher::nbPrimitiveTypes> firstIndex, baseInstance;
            for (unsigned int i = 0; i < firstIndex.size(); i++) {
                firstIndex[i] = 0;
            }
            for (unsigned int i = 0; i < baseInstance.size(); i++) {
                baseInstance[i] = 0;
            }
            for (unsigned int i = 0; i < m_instances.size(); i++) {
                if (m_instances[i].getAllVertices().getVertexCount() > 0) {
                    DrawArraysIndirectCommand drawArraysIndirectCommand;
                    unsigned int p = m_instances[i].getAllVertices().getPrimitiveType();
                    if (core::Application::app != nullptr) {
                        float time = core::Application::getTimeClk().getElapsedTime().asSeconds();
                        perPixelLinkedList.setParameter("time", time);
                    }
                    std::vector<TransformMatrix*> tm = m_instances[i].getTransforms();
                    for (unsigned int j = 0; j < tm.size(); j++) {
                        tm[j]->update();
                        std::array<float, 16> matrix = tm[j]->getMatrix().transpose().toGlMatrix();
                        for (unsigned int n = 0; n < 16; n++) {
                            matrices[p].push_back(matrix[n]);
                        }
                    }
                    unsigned int vertexCount = 0;
                    if (m_instances[i].getVertexArrays().size() > 0) {
                        Entity* entity = m_instances[i].getVertexArrays()[0]->getEntity();
                        for (unsigned int j = 0; j < m_instances[i].getVertexArrays().size(); j++) {
                            if (entity == m_instances[i].getVertexArrays()[j]->getEntity()) {
                                for (unsigned int k = 0; k < m_instances[i].getVertexArrays()[j]->getVertexCount(); k++) {
                                    vertexCount++;
                                    vbBindlessTex[p].append((*m_instances[i].getVertexArrays()[j])[k], (m_instances[i].getMaterial().getTexture() != nullptr) ? m_instances[i].getMaterial().getTexture()->getId() : 0);
                                    vbBindlessTex[p].addMaterialType(m_instances[i].getMaterial().getType());
                                }
                            }
                        }
                    }
                    drawArraysIndirectCommand.count = vertexCount;
                    drawArraysIndirectCommand.firstIndex = firstIndex[p];
                    drawArraysIndirectCommand.baseInstance = baseInstance[p];
                    drawArraysIndirectCommand.instanceCount = tm.size();
                    drawArraysIndirectCommands[p].push_back(drawArraysIndirectCommand);
                    firstIndex[p] += vertexCount;
                    baseInstance[p] += tm.size();
                    //std::cout<<"texture : "<<m_instances[i].getMaterial().getTexture()<<std::endl;
                    //std::cout<<"entity : "<<m_instances[i].getVertexArrays()[0]->getEntity()->getRootEntity()->getType()<<std::endl;

                }
            }
            for (unsigned int i = 0; i < m_normals.size(); i++) {
                if (m_normals[i].getAllVertices().getVertexCount() > 0) {
                    DrawArraysIndirectCommand drawArraysIndirectCommand;
                    unsigned int p = m_normals[i].getAllVertices().getPrimitiveType();
                    if (core::Application::app != nullptr) {
                        float time = core::Application::getTimeClk().getElapsedTime().asSeconds();
                        perPixelLinkedList.setParameter("time", time);
                    }
                    unsigned int vertexCount = 0;
                    if (m_normals[i].getVertexArrays().size() > 0) {
                        for (unsigned int j = 0; j < m_normals[i].getVertexArrays().size(); j++) {
                            for (unsigned int k = 0; k < m_normals[i].getVertexArrays()[j]->getVertexCount(); k++) {
                                vertexCount++;
                                vbBindlessTex[p].append((*m_normals[i].getVertexArrays()[j])[k], (m_normals[i].getMaterial().getTexture() != nullptr) ? m_normals[i].getMaterial().getTexture()->getId() : 0);
                                vbBindlessTex[p].addMaterialType(m_normals[i].getMaterial().getType());
                                TransformMatrix* tm = m_normals[i].getPerVaTransforms()[j];
                                tm->update();
                                std::array<float, 16> matrix = tm->getMatrix().transpose().toGlMatrix();
                                for (unsigned int n = 0; n < 16; n++) {
                                    matrices[p].push_back(matrix[n]);
                                }
                            }
                        }
                    }
                    drawArraysIndirectCommand.count = vertexCount;
                    drawArraysIndirectCommand.firstIndex = firstIndex[p];
                    drawArraysIndirectCommand.baseInstance = baseInstance[p];
                    drawArraysIndirectCommand.instanceCount = 0;
                    drawArraysIndirectCommands[p].push_back(drawArraysIndirectCommand);
                    firstIndex[p] += vertexCount;
                    //std::cout<<"texture : "<<m_instances[i].getMaterial().getTexture()<<std::endl;
                    //std::cout<<"entity : "<<m_instances[i].getVertexArrays()[0]->getEntity()->getRootEntity()->getType()<<std::endl;

                }
            }
            currentStates.blendMode = sf::BlendNone;
            currentStates.shader = &indirectRenderingShader;
            currentStates.texture = nullptr;
            for (unsigned int p = 0; p < Batcher::nbPrimitiveTypes; p++) {
                if (vbBindlessTex[p].getVertexCount() > 0) {
                    glCheck(glBindBuffer(GL_SHADER_STORAGE_BUFFER, matricesBuffer));
                    glCheck(glBufferData(GL_SHADER_STORAGE_BUFFER, matrices[p].size() * sizeof(float), &matrices[p][0], GL_DYNAMIC_DRAW));
                    glCheck(glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0));
                    glCheck(glBindBuffer(GL_DRAW_INDIRECT_BUFFER, vboIndirect));
                    glCheck(glBufferData(GL_DRAW_INDIRECT_BUFFER, drawArraysIndirectCommands[p].size() * sizeof(DrawArraysIndirectCommand), &drawArraysIndirectCommands[p][0], GL_DYNAMIC_DRAW));
                    glCheck(glBindBuffer(GL_DRAW_INDIRECT_BUFFER, 0));
                    vbBindlessTex[p].update();
                    frameBuffer.drawIndirect(vbBindlessTex[p], vbBindlessTex[p].getPrimitiveType(), drawArraysIndirectCommands[p].size(), currentStates, vboIndirect);
                    vbBindlessTex[p].clear();
                }
            }
        }

The draw indirect function :

 void RenderTarget::drawIndirect(VertexBuffer& vertexBuffer, enum sf::PrimitiveType type, unsigned int nbIndirectCommands, RenderStates states, unsigned int vboIndirect, unsigned int vboMatrix1, unsigned int vboMatrix2) {
            if (vertexBuffer.getVertexCount() == 0) {
                return;
            }

            if (activate(true))
            {
                if (!m_cache.glStatesSet)
                    resetGLStates();
                // Apply the view
                if (m_cache.viewChanged)
                    applyCurrentView();

                if (states.blendMode != m_cache.lastBlendMode)
                    applyBlendMode(states.blendMode);

                // Apply the texture
                sf::Uint64 textureId = states.texture ? states.texture->getNativeHandle() : 0;
                if (textureId != m_cache.lastTextureId)
                    applyTexture(states.texture);
                // Apply the shader
                if (states.shader)
                    applyShader(states.shader);
                if (m_versionMajor > 3 || m_versionMajor == 3 && m_versionMinor >= 3)
                    glCheck(glBindVertexArray(m_vao));
                if (m_cache.lastVboBuffer != &vertexBuffer) {
                    if (m_versionMajor > 3 || m_versionMajor == 3 && m_versionMinor >= 3) {
                        glCheck(glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer.vboVertexBuffer));
                        glCheck(glEnableVertexAttribArray(0));
                        glCheck(glEnableVertexAttribArray(1));
                        glCheck(glEnableVertexAttribArray(2));
                        glCheck(glVertexAttribPointer(0, 3,GL_FLOAT,GL_FALSE,sizeof(Vertex), (GLvoid*) 0));
                        glCheck(glVertexAttribPointer(1, 4,GL_UNSIGNED_BYTE,GL_TRUE,sizeof(Vertex),(GLvoid*) 12));
                        glCheck(glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*) 16));
                        glCheck(glEnableVertexAttribArray(3));
                        glCheck(glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer.vboNormalBuffer));
                        glCheck(glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, sizeof(sf::Vector3f), (GLvoid*) 0));
                        glCheck(glDisableVertexAttribArray(0));
                        glCheck(glDisableVertexAttribArray(1));
                        glCheck(glDisableVertexAttribArray(2));
                        glCheck(glDisableVertexAttribArray(3));
                        glCheck(glBindBuffer(GL_ARRAY_BUFFER, 0));

                        /*va_list args;
                        va_start(args, n);
                        for (unsigned int i = 0; i < n; i++) {
                            unsigned int vboMatrices = va_arg(args, unsigned int);
                            for (unsigned int j = 0; j < 4; j++) {
                                glCheck(glEnableVertexAttribArray(i * 4 + j + 3));
                                glCheck(glBindBuffer(GL_ARRAY_BUFFER, vboMatrices));
                                glCheck(glVertexAttribPointer(i * 4 + j + 3, 4, GL_FLOAT, GL_FALSE, sizeof(math::Matrix4f),
                                                        (const GLvoid*)(sizeof(GLfloat) * i * 4)));
                                glCheck(glBindBuffer(GL_ARRAY_BUFFER, 0));
                                glCheck(glVertexAttribDivisor(i * 4 + j + 3, 1));
                                glCheck(glDisableVertexAttribArray(i * 4 + j + 3));
                            }
                        }
                        va_end(args);*/
                        if (vboMatrix1 != 0) {
                            for (unsigned int i = 0; i < 4; i++) {
                                glCheck(glEnableVertexAttribArray(i + 4));
                                glCheck(glBindBuffer(GL_ARRAY_BUFFER, vboMatrix1));
                                glCheck(glVertexAttribPointer(i + 4, 4, GL_FLOAT, GL_FALSE, sizeof(math::Matrix4f),
                                                        (const GLvoid*)(sizeof(GLfloat) * i * 4)));
                                glCheck(glBindBuffer(GL_ARRAY_BUFFER, 0));
                                glCheck(glVertexAttribDivisor(i + 4, 1));
                                glCheck(glDisableVertexAttribArray(i + 4));
                            }
                        }
                        if (vboMatrix2 != 0) {
                            for (unsigned int i = 0; i < 4; i++) {
                                glCheck(glEnableVertexAttribArray(i + 8));
                                glCheck(glBindBuffer(GL_ARRAY_BUFFER, vboMatrix2));
                                glCheck(glVertexAttribPointer(i + 8, 4, GL_FLOAT, GL_FALSE, sizeof(math::Matrix4f),
                                                        (const GLvoid*)(sizeof(GLfloat) * i * 4)));
                                glCheck(glBindBuffer(GL_ARRAY_BUFFER, 0));
                                glCheck(glVertexAttribDivisor(i + 8, 1));
                                glCheck(glDisableVertexAttribArray(i + 8));
                            }
                        }
                        glCheck(glEnableVertexAttribArray(12));
                        glCheck(glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer.vboTextureIndexesBuffer));
                        glCheck(glVertexAttribIPointer(12, 1, GL_UNSIGNED_INT, sizeof(GLuint), (GLvoid*) 0));
                        glCheck(glDisableVertexAttribArray(12));
                        glCheck(glBindBuffer(GL_ARRAY_BUFFER, 0));
                        if (vertexBuffer.vboMaterialType != 0) {
                            glCheck(glEnableVertexAttribArray(13));
                            glCheck(glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer.vboMaterialType));
                            glCheck(glVertexAttribIPointer(13, 1, GL_UNSIGNED_INT, sizeof(GLuint), (GLvoid*) 0));
                            glCheck(glDisableVertexAttribArray(13));
                            glCheck(glBindBuffer(GL_ARRAY_BUFFER, 0));
                        }
                        if (vertexBuffer.vboLayer != 0) {
                            glCheck(glEnableVertexAttribArray(14));
                            glCheck(glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer.vboMaterialType));
                            glCheck(glVertexAttribIPointer(14, 1, GL_UNSIGNED_INT, sizeof(GLuint), (GLvoid*) 0));
                            glCheck(glDisableVertexAttribArray(14));
                            glCheck(glBindBuffer(GL_ARRAY_BUFFER, 0));
                        }
                        if (vertexBuffer.vboSpecular != 0) {
                            glCheck(glEnableVertexAttribArray(15));
                            glCheck(glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer.vboSpecular));
                            glCheck(glVertexAttribPointer(15, 2, GL_FLOAT,GL_FALSE,sizeof(sf::Vector2f),(GLvoid*) 0));
                            glCheck(glDisableVertexAttribArray(15));
                            glCheck(glBindBuffer(GL_ARRAY_BUFFER, 0));
                        }
                    }
                    m_cache.lastVboBuffer = &vertexBuffer;

                }
                if (m_versionMajor > 3 || m_versionMajor == 3 && m_versionMinor >= 3) {
                    glCheck(glEnableVertexAttribArray(0));
                    glCheck(glEnableVertexAttribArray(1));
                    glCheck(glEnableVertexAttribArray(2));
                    glCheck(glEnableVertexAttribArray(3));
                    if (vboMatrix1 != 0) {
                        for (unsigned int i = 0; i < 4 ; i++) {
                            glCheck(glEnableVertexAttribArray(4 + i));
                        }
                    }
                    if (vboMatrix2 != 0) {
                        for (unsigned int i = 0; i < 4 ; i++) {
                            glCheck(glEnableVertexAttribArray(8 + i));
                        }
                    }
                    glCheck(glEnableVertexAttribArray(12));
                    if (vertexBuffer.vboMaterialType != 0) {
                        glCheck(glEnableVertexAttribArray(13));
                    }
                    if (vertexBuffer.vboLayer != 0) {
                        glCheck(glEnableVertexAttribArray(14));
                    }
                    if (vertexBuffer.vboSpecular != 0) {
                        glCheck(glEnableVertexAttribArray(15));
                    }
                    static const GLenum modes[] = {GL_POINTS, GL_LINES, GL_LINE_STRIP, GL_TRIANGLES,
                                                       GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN, GL_QUADS};
                    GLenum mode = modes[type];
                    glCheck(glBindFramebuffer(GL_FRAMEBUFFER, m_framebufferId));
                    glCheck(glBindBuffer(GL_DRAW_INDIRECT_BUFFER, vboIndirect));
                    if (vertexBuffer.getIndexes().size() == 0) {
                        glCheck(glMultiDrawArraysIndirect(mode,0,nbIndirectCommands,0));
                    } else {
                        glCheck(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vertexBuffer.vboIndexBuffer));
                        glCheck(glMultiDrawElementsIndirect(mode, GL_UNSIGNED_INT, 0, nbIndirectCommands, 0));
                        glCheck(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
                    }
                    glCheck(glBindBuffer(GL_DRAW_INDIRECT_BUFFER, 0));
                    glCheck(glDisableVertexAttribArray(0));
                    glCheck(glDisableVertexAttribArray(1));
                    glCheck(glDisableVertexAttribArray(2));
                    glCheck(glDisableVertexAttribArray(3));
                    if (vboMatrix1 != 0) {
                        for (unsigned int i = 0; i < 4 ; i++) {
                            glCheck(glDisableVertexAttribArray(4 + i));
                        }
                    }
                    if (vboMatrix2 != 0) {
                        for (unsigned int i = 0; i < 4 ; i++) {
                            glCheck(glDisableVertexAttribArray(8 + i));
                        }
                    }
                    glCheck(glDisableVertexAttribArray(12));
                    if (vertexBuffer.vboMaterialType != 0) {
                        glCheck(glDisableVertexAttribArray(13));
                    }
                    if (vertexBuffer.vboLayer != 0) {
                        glCheck(glDisableVertexAttribArray(14));
                    }
                    if (vertexBuffer.vboSpecular != 0) {
                        glCheck(glDisableVertexAttribArray(15));
                    }
                    glCheck(glBindVertexArray(0));
                }
            }
            applyTexture(nullptr);
            applyShader(nullptr);
        }

And in my vertex shader it seems that the SSBO is empty, but when I use a VBO it draws only instanced stuff because of the vertexAttribDivisor probably.

indirectVertexShader:

#version 460
#define M_PI 3.1415926535897932384626433832795
#define FPI M_PI/4
layout (location = 0) in vec3 position;
layout (location = 1) in vec4 color;
layout (location = 2) in vec2 texCoords;
layout (location = 3) in vec3 normals;
layout (location = 4) in mat4 worldMat;
layout (location = 12) in uint textureIndex;
layout (location = 13) in uint materialType;
uniform mat4 projectionMatrix;
uniform mat4 viewMatrix;
uniform mat4 textureMatrix[ /* core::conversionUIntString(Texture::getAllTextures().size()) */ ];
uniform float time;
uniform vec3 resolution;
out vec2 fTexCoords;
out vec4 frontColor;
out uint texIndex;
struct Matrix {
    mat4 worldMat;
};
layout(binding = 1, std430) buffer matricesBuffer {
   Matrix matrices[];
};
void main() {
    float xOff = 0;
    float yOff = 0;
    if (materialType == 1) {
        yOff = 0.05*sin(position.x*12+time*FPI)*resolution.y;
        xOff = 0.025*cos(position.x*12+time*FPI)*resolution.x;
    }
    gl_Position = projectionMatrix * viewMatrix * matrices[gl_BaseInstance + gl_InstanceID].worldMat * vec4((position.x - xOff), (position.y + yOff), position.z, 1.f);
    fTexCoords = (textureIndex != 0) ? (textureMatrix[textureIndex-1] * vec4(texCoords, 1.f, 1.f)).xy : texCoords;
    frontColor = color;
    texIndex = textureIndex;
}

I bind the SSBO and I fill the SSBO before drawing stuff why it doen’t draw nothing ?
I need to draw instanced stuff and non instanced stuff seperatly otherwise that doens’t work.
It’s really anoying because I have 4 draw functions (with indices) instead of 2.
The only thing I change is using an SSBO instead of a VBO and using gl_InstanceBase and gl_InstanceID

If I forgot to pass projection and view matrices to shader it’ll not work.
But the driver crash when I want to draw non instanced stuff :

void PerPixelLinkedListRenderComponent::drawInstances() {
            for (unsigned int i = 0; i < Batcher::nbPrimitiveTypes; i++) {
                vbBindlessTex[i].clear();
            }

            std::array<std::vector<DrawArraysIndirectCommand>, Batcher::nbPrimitiveTypes> drawArraysIndirectCommands;
            std::array<std::vector<Matrix>, Batcher::nbPrimitiveTypes> matrices;
            std::array<unsigned int, Batcher::nbPrimitiveTypes> firstIndex, baseInstance;
            for (unsigned int i = 0; i < firstIndex.size(); i++) {
                firstIndex[i] = 0;
            }
            for (unsigned int i = 0; i < baseInstance.size(); i++) {
                baseInstance[i] = 0;
            }
            for (unsigned int i = 0; i < m_instances.size(); i++) {
                if (m_instances[i].getAllVertices().getVertexCount() > 0) {
                    DrawArraysIndirectCommand drawArraysIndirectCommand;
                    unsigned int p = m_instances[i].getAllVertices().getPrimitiveType();
                    if (core::Application::app != nullptr) {
                        float time = core::Application::getTimeClk().getElapsedTime().asSeconds();
                        indirectRenderingShader.setParameter("time", time);
                    }
                    std::vector<TransformMatrix*> tm = m_instances[i].getTransforms();
                    for (unsigned int j = 0; j < tm.size(); j++) {
                        tm[j]->update();
                        Matrix matrix;
                        matrix.worldMat = tm[j]->getMatrix().transpose();
                        matrices[p].push_back(matrix);
                    }
                    unsigned int vertexCount = 0;
                    if (m_instances[i].getVertexArrays().size() > 0) {
                        Entity* entity = m_instances[i].getVertexArrays()[0]->getEntity();
                        for (unsigned int j = 0; j < m_instances[i].getVertexArrays().size(); j++) {
                            if (entity == m_instances[i].getVertexArrays()[j]->getEntity()) {
                                for (unsigned int k = 0; k < m_instances[i].getVertexArrays()[j]->getVertexCount(); k++) {
                                    vertexCount++;
                                    vbBindlessTex[p].append((*m_instances[i].getVertexArrays()[j])[k], (m_instances[i].getMaterial().getTexture() != nullptr) ? m_instances[i].getMaterial().getTexture()->getId() : 0);
                                    vbBindlessTex[p].addMaterialType(m_instances[i].getMaterial().getType());
                                }
                            }
                        }
                    }
                    drawArraysIndirectCommand.count = vertexCount;
                    drawArraysIndirectCommand.firstIndex = firstIndex[p];
                    drawArraysIndirectCommand.baseInstance = baseInstance[p];
                    drawArraysIndirectCommand.instanceCount = tm.size();
                    drawArraysIndirectCommands[p].push_back(drawArraysIndirectCommand);
                    firstIndex[p] += vertexCount;
                    baseInstance[p] += tm.size();
                    //std::cout<<"texture : "<<m_instances[i].getMaterial().getTexture()<<std::endl;
                    //std::cout<<"entity : "<<m_instances[i].getVertexArrays()[0]->getEntity()->getRootEntity()->getType()<<std::endl;

                }
            }
            for (unsigned int i = 0; i < m_normals.size(); i++) {
                if (m_normals[i].getAllVertices().getVertexCount() > 0) {
                    DrawArraysIndirectCommand drawArraysIndirectCommand;
                    unsigned int p = m_normals[i].getAllVertices().getPrimitiveType();
                    if (core::Application::app != nullptr) {
                        float time = core::Application::getTimeClk().getElapsedTime().asSeconds();
                        indirectRenderingShader.setParameter("time", time);
                    }

                    unsigned int vertexCount = 0;
                    if (m_normals[i].getVertexArrays().size() > 0) {
                        for (unsigned int j = 0; j < m_normals[i].getVertexArrays().size(); j++) {
                            for (unsigned int k = 0; k < m_normals[i].getVertexArrays()[j]->getVertexCount(); k++) {
                                vertexCount++;
                                vbBindlessTex[p].append((*m_normals[i].getVertexArrays()[j])[k], (m_normals[i].getMaterial().getTexture() != nullptr) ? m_normals[i].getMaterial().getTexture()->getId() : 0);
                                vbBindlessTex[p].addMaterialType(m_normals[i].getMaterial().getType());
                                TransformMatrix* tm = m_normals[i].getPerVaTransforms()[j];
                                tm->update();
                                Matrix matrix;
                                matrix.worldMat = tm->getMatrix().transpose();
                                matrices[p].push_back(matrix);

                            }
                        }
                    }
                    drawArraysIndirectCommand.count = vertexCount;
                    drawArraysIndirectCommand.firstIndex = firstIndex[p];
                    drawArraysIndirectCommand.baseInstance = baseInstance[p];
                    drawArraysIndirectCommand.instanceCount = 0;
                    drawArraysIndirectCommands[p].push_back(drawArraysIndirectCommand);
                    firstIndex[p] += vertexCount;
                    //std::cout<<"texture : "<<m_instances[i].getMaterial().getTexture()<<std::endl;
                    //std::cout<<"entity : "<<m_instances[i].getVertexArrays()[0]->getEntity()->getRootEntity()->getType()<<std::endl;

                }
            }
            currentStates.blendMode = sf::BlendNone;
            currentStates.shader = &indirectRenderingShader;
            currentStates.texture = nullptr;
            for (unsigned int p = 0; p < Batcher::nbPrimitiveTypes; p++) {
                if (vbBindlessTex[p].getVertexCount() > 0) {
                    glCheck(glBindBuffer(GL_SHADER_STORAGE_BUFFER, matricesBuffer));
                    glCheck(glBufferData(GL_SHADER_STORAGE_BUFFER, matrices[p].size() * sizeof(Matrix), &matrices[p][0], GL_DYNAMIC_DRAW));
                    glCheck(glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0));
                    glCheck(glBindBuffer(GL_DRAW_INDIRECT_BUFFER, vboIndirect));
                    glCheck(glBufferData(GL_DRAW_INDIRECT_BUFFER, drawArraysIndirectCommands[p].size() * sizeof(DrawArraysIndirectCommand), &drawArraysIndirectCommands[p][0], GL_DYNAMIC_DRAW));
                    glCheck(glBindBuffer(GL_DRAW_INDIRECT_BUFFER, 0));
                    vbBindlessTex[p].update();
                    frameBuffer.drawIndirect(vbBindlessTex[p], vbBindlessTex[p].getPrimitiveType(), drawArraysIndirectCommands[p].size(), currentStates, vboIndirect);
                    vbBindlessTex[p].clear();
                }
            }
        }

I think the problem is that gl_BaseInstance and gl_InstanceID are set to 0 when I want to draw non instanced stuff thus I think I need to draw them separatly.

If you’re using indirect rendering, there’s no such thing as “non-instanced” drawing. Indirect rendering data always includes instance parameters. If gl_BaseInstance is zero, that’s because you set it to zero.

So… stop doing that. Set your values properly, and you’ll be fine.

So I guess some variables are not set properly but when I look at the code everything seems to be fine so don’t understand normally it should add gl_VetexID to gl_BaseInstance I set gl_BaseInstance to the number of instances at the end of instances drawing.
But it doesn’t seems to get the right matrix in the shader.

… that’s not how instancing works.

Do you? Your code is kind of a mess, so I don’t really want to sift through it. Put a breakpoint at the moment when you’re about to upload the drawing commands and make sure that the data you’re sending is what you expect it to be. Only the first drawing command should have a base instance value of 0.