GlDrawElementsInstanced freezes or slows down on 18680 instances

I am developing a C ++ program to simulate rain. I am using the OpenGL instance feature to increase the number of blobs. (One copy = one drop)

The program runs fine when called glDrawElementsInstances

until the number of instances reaches 18680. Then it freezes or produces strange behavior (huge slump, incoherent rendering of instances).

My render loop:

GLObject GLDrop(*this->_model._drop, *this->_shader); // generate buffer
while (!glfwWindowShouldClose(this->_window))
{
     glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
     this->_model._drop->create();
     GLDrop.setDropState();
     glDrawElementsInstanced(GL_TRIANGLE_STRIP, this->_model._drop->getElementsSize(), GL_UNSIGNED_INT, 0, this->_model._drop->getInstances());
     GLDrop.disableDropState();
     glfwSwapBuffers(this->_window);
     glfwPollEvents();
}

      

Buffer generation function, called just before the render loop:

void            GLObject::generateDropBuffers(void)
{
    glGenBuffers(1, &this->_vbo);
    glBindBuffer(GL_ARRAY_BUFFER, this->_vbo);
    glBufferData(GL_ARRAY_BUFFER, this->_module.getVerticesSize() * sizeof(GLfloat), this->_module.getVertices(), GL_STATIC_DRAW);

    glGenBuffers(1, &this->_ebo);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this->_ebo);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, this->_module.getElementsSize() * sizeof(GLuint), this->_module.getElements(), GL_STATIC_DRAW);

    glGenBuffers(1, &this->_pbo);
    glBindBuffer(GL_ARRAY_BUFFER, this->_pbo);
    glBufferData(GL_ARRAY_BUFFER, this->_module.getMaxInstances() * DIMENSIONS * sizeof(GLfloat), NULL, GL_DYNAMIC_DRAW);

    glGenBuffers(1, &this->_cbo);
    glBindBuffer(GL_ARRAY_BUFFER, this->_cbo);
    glBufferData(GL_ARRAY_BUFFER, this->_module.getMaxInstances() * COLOR_CHANNELS * sizeof(GLfloat), NULL, GL_DYNAMIC_DRAW);
}

      

Each time Drop.create () is called, a new batch of drops is created, increasing the number of instances to be drawn on the screen.

void            Drop::create(void)
{
    unsigned int    i;
    unsigned int    j;

    if (this->_instances < this->_maxInstances - this->_dropBatch)
    {
        for (GLuint drop = 0; drop < this->_dropBatch; ++drop)
        {
           i = this->_instances * DIMENSIONS;
           j = this->_instances * COLOR_CHANNELS;

           this->_positions[i] = rand() % this->_model._vertexCol * UNIT;
           this->_positions[i + 1] = this->_model._top + 3.0f * UNIT;
           this->_positions[i + 2] = rand() % this->_model._vertexRow * UNIT;

           this->_colors[j] = 0.0f;
           this->_colors[j + 1] = 0.0f;
           this->_colors[j + 2] = 1.0f;
           this->_colors[j + 3] = 1.0f; 
           this->_instances += 1;
        }
     }
}

      

My buffer binding function:

void            GLObject::setDropState(void)
{
    GLuint      instances = this->_module.getInstances() - this->_module.getBatchSize();
    GLuint      posOffset = instances * DIMENSIONS;
    GLuint      colorOffset = instances * COLOR_CHANNELS;
    GLuint      posSize = this->_module.getBatchSize() * DIMENSIONS * sizeof(GLfloat);
    GLuint      colorSize = this->_module.getBatchSize() * COLOR_CHANNELS * sizeof(GLfloat);

    glBindBuffer(GL_ARRAY_BUFFER, this->_vbo);
    glVertexAttribPointer(this->_shader.getAPosition(), DIMENSIONS, GL_FLOAT, GL_FALSE, 0, 0);
    glEnableVertexAttribArray(this->_shader.getAPosition());

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this->_ebo);

    glBindBuffer(GL_ARRAY_BUFFER, this->_pbo);
    glBufferSubData(GL_ARRAY_BUFFER, posOffset * sizeof(GLfloat), posSize, this->_module.getPositions() + posOffset);
    glVertexAttribPointer(this->_shader.getAInstance(), DIMENSIONS, GL_FLOAT, GL_FALSE, 0, 0);
    glEnableVertexAttribArray(this->_shader.getAInstance());

    glBindBuffer(GL_ARRAY_BUFFER, this->_cbo);
    glBufferSubData(GL_ARRAY_BUFFER, colorOffset * sizeof(GLfloat), colorSize, this->_module.getColors() + colorOffset);
    glVertexAttribPointer(this->_shader.getAColors(), COLOR_CHANNELS, GL_FLOAT, GL_FALSE, 0, 0);
    glEnableVertexAttribArray(this->_shader.getAColors());

    glVertexAttribDivisor(this->_shader.getAPosition(), 0);
    glVertexAttribDivisor(this->_shader.getAInstance(), 1);
    glVertexAttribDivisor(this->_shader.getAColors(), 1);
}

      

Tested:

NVIDIA GeForce GT 330M 512MB, MacbookPro.

NVIDIA GeForce 9400M 256MB, MacbookPro

I do not know what's the problem. Is there a limit to the number of instances that I can make in one call? (I highly doubt this is the case). I am using buffers a lot more than I need to to make sure this is not a memory access issue.

Could this be a memory alignment issue?

The OpenGL Manual says it, but I can't figure it out.

Clients must negotiate items as required by the client platform, with the additional baseline requirement that the offset within the buffer to a database containing N bytes is a multiple of H.

Any help would be greatly appreciated.

My scene with 18860 instances of drops drawn, before crashing

my scene EDIT:

While searching on google i found a similar case: https://www.opengl.org/discussion_boards/showthread.php/181142-glDrawArraysInstanced-max-number-of-instances

The author of the thread has the same problem as me, but accurate to the number of instances (I think because his GPU memory is 512, not 256). Moreover, I found that I have different behaviors depending on how many instances I add each loop.

For example: If I add 100 instances per cycle, my program will freeze. If I add 200 or more instances per loop, my program slows down to 4fps.

At the bottom of the link posted above, authour explains in detail the reason for this behavior. Apparently the difference is due to the jump (or not) of a certain interval of instances. If I add 100 copies per cycle, I get into the death tier (so freeze), but if I add more than 100, I jump over the death gap (slows down so much)

Any idea about this weird macbook "bug"?

+3


source to share


1 answer


I have similar problems with glDrawElementsInstancedEXT (iPhone 5). I tried different networks and found out that FPS drops a hundred times if the total number of indices (number of instances times number of grid indices) exceeds about 4 million. I would add that drawing using glDrawElements slows down similarly in this case.

And there is one more problem. If the number of instances exceeds 65535, glDrawElementsInstancedEXT draws based on the number of instances drawn in the very first call to glDrawElementsInstancedEXT:



  • if the number of instances in the very first call is less than 65536, then the next calls only draw the first 65535 instances

  • if the number of instances in the very first call exceeds 65535, then the next calls dial the full number of instances.

It looks like a bug in the driver.

0


source







All Articles