Advertisement

glDrawElements GL_INVALID_OPERATION on AMD GPU

Started by December 25, 2019 03:09 PM
11 comments, last by fleabay 5Β years ago

Hello! I wrote a small engine, and decided to test it on different graphics cards. And here is what turned out to be unexpected: on Nvidia and Intel everything works well on Linux and Windows, but on AMD - it gives error 1282 (GL_INVALID_OPERATION) when trying to call glDrawElements. Below are code snippets and links to the full one.

void drawModelDM(const Model &model, ShaderProgram *program, const glm::mat4 &mat = glm::mat4(1.0f)) {
    glBindVertexArray(model.shape->vaos[0]);

    if (model.shape->bonesPerVertex != 0) {
        for (int i = 0; i < model.shape->bones.size(); i++) {
            program->set(program->getLocation(AlgineNames::ShadowShader::Bones) + i, model.shape->bones[i].finalTransformation);
        }
    }

    program->set(AlgineNames::ShadowShader::BoneAttribsPerVertex, (int)(model.shape->bonesPerVertex / 4 + (model.shape->bonesPerVertex % 4 == 0 ? 0 : 1)));
    program->set(AlgineNames::ShadowShader::TransformationMatrix, mat * model.m_transform);
    
    for (size_t i = 0; i < model.shape->meshes.size(); i++) {
        int err = glGetError();
        if (err != 0)
            std::cout << "Before glDrawElements DM: " << err << "\n";
        glDrawElements(GL_TRIANGLES, model.shape->meshes[i].count, GL_UNSIGNED_INT, reinterpret_cast<void*>(model.shape->meshes[i].start * sizeof(uint))); // OK
        err = glGetError();
        if (err != 0)
            std::cout << "After glDrawElements DM: " << err << "\n";
    }
}

/**
 * Draws model
 */
void drawModel(const Model &model) {
    glBindVertexArray(model.shape->vaos[1]);

    if (model.shape->bonesPerVertex != 0) {
        for (int i = 0; i < model.shape->bones.size(); i++) {
            colorShader->set(colorShader->getLocation(AlgineNames::ColorShader::Bones) + i, model.shape->bones[i].finalTransformation);
        }
    }

    colorShader->set(AlgineNames::ColorShader::BoneAttribsPerVertex, (int)(model.shape->bonesPerVertex / 4 + (model.shape->bonesPerVertex % 4 == 0 ? 0 : 1)));
    modelMatrix = &model.m_transform;
   updateMatrices();
    for (size_t i = 0; i < model.shape->meshes.size(); i++) {
        texture2DAB(0, model.shape->meshes[i].mat.ambientTexture);
        texture2DAB(1, model.shape->meshes[i].mat.diffuseTexture);
        texture2DAB(2, model.shape->meshes[i].mat.specularTexture);
        texture2DAB(3, model.shape->meshes[i].mat.normalTexture);
        texture2DAB(4, model.shape->meshes[i].mat.reflectionTexture);
        texture2DAB(5, model.shape->meshes[i].mat.jitterTexture);

        colorShader->set(AlgineNames::ColorShader::Material::AmbientStrength, model.shape->meshes[i].mat.ambientStrength);
        colorShader->set(AlgineNames::ColorShader::Material::DiffuseStrength, model.shape->meshes[i].mat.diffuseStrength);
        colorShader->set(AlgineNames::ColorShader::Material::SpecularStrength, model.shape->meshes[i].mat.specularStrength);
        colorShader->set(AlgineNames::ColorShader::Material::Shininess, model.shape->meshes[i].mat.shininess);

        int err = glGetError();
        if (err != 0)
            std::cout << "Before glDrawElements: " << err << "\n";
        glDrawElements(GL_TRIANGLES, model.shape->meshes[i].count, GL_UNSIGNED_INT, reinterpret_cast<void*>(model.shape->meshes[i].start * sizeof(uint))); // ERROR: 1282
        err = glGetError();
        if (err != 0)
            std::cout << "After glDrawElements: " << err
                << "\nCount: " << model.shape->meshes[i].count
                << "\nStart: " << model.shape->meshes[i].start
                << "\nVAO: " << model.shape->vaos[1] << "\n";
    }
}

/**
 * Renders to depth cubemap
 */
void renderToDepthCubemap(const uint index) {
   pointLamps[index].begin();
    pointLamps[index].updateMatrix();
    lightDataSetter.setShadowShaderPos(pointLamps[index]);
   lightDataSetter.setShadowShaderMatrices(pointLamps[index]);
   glClear(GL_DEPTH_BUFFER_BIT);

   // drawing models
    for (size_t i = 0; i < MODELS_COUNT; i++)
        drawModelDM(models[i], pointShadowShader);

   // drawing lamps
   for (GLuint i = 0; i < pointLampsCount; i++) {
      if (i == index) continue;
        drawModelDM(*pointLamps[i].mptr, pointShadowShader);
   }

   pointLamps[index].end();
}

/**
 * Renders to depth map
 */
void renderToDepthMap(uint index) {
   dirLamps[index].begin();
   glClear(GL_DEPTH_BUFFER_BIT);

   // drawing models
    for (size_t i = 0; i < MODELS_COUNT; i++)
        drawModelDM(models[i], dirShadowShader, dirLamps[index].m_lightSpace);

   // drawing lamps
   for (GLuint i = 0; i < dirLampsCount; i++) {
      if (i == index) continue;
        drawModelDM(*dirLamps[i].mptr, dirShadowShader, dirLamps[index].m_lightSpace);
   }

   dirLamps[index].end();
}

/**
 * Color rendering
 */
uint colorAttachment02[3] = { GL_COLOR_ATTACHMENT0, GL_NONE, GL_COLOR_ATTACHMENT2 };
uint colorAttachment0123[4] = {
    GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2, GL_COLOR_ATTACHMENT3
};
void render() {
    renderer.mainPass(displayFb->getId());
    
   // view port to window size
   glViewport(0, 0, winWidth, winHeight);

    glDrawBuffers(4, colorAttachment0123);
    colorShader->use();

    // sending lamps parameters to fragment shader
   sendLampsData();

    // drawing
    for (size_t i = 0; i < MODELS_COUNT; i++)
        drawModel(models[i]);
   for (size_t i = 0; i < pointLampsCount + dirLampsCount; i++)
       drawModel(lamps[i]);

    // [...]
}

void display() {
    // animate
    for (usize i = 0; i < MODELS_COUNT; i++)
        if (models[i].shape->bonesPerVertex != 0)
            models[i].animator->animate(glfwGetTime());

    // shadow rendering
    // point lights
    pointShadowShader->use();
   for (uint i = 0; i < pointLampsCount; i++) {
       lightDataSetter.setShadowShaderFarPlane(pointLamps[i]);
        renderToDepthCubemap(i);
    }

    // dir lights
    dirShadowShader->use();
    for (uint i = 0; i < dirLampsCount; i++)
        renderToDepthMap(i);
   
    ssrShader->use();
    ssrShader->set(AlgineNames::SSRShader::ProjectionMatrix, camera.getProjectionMatrix());
    ssrShader->set(AlgineNames::SSRShader::ViewMatrix, camera.getViewMatrix());

   /* --- color rendering --- */
    glClear(GL_DEPTH_BUFFER_BIT); // color will cleared by quad rendering
   render();
   glUseProgram(0);
}

Everything is perfectly drawn in the depth map, but not in the "color map"... And such a problem is ONLY on AMD.

Full code: https://github.com/congard/algine/blob/master/src/main.cpp#L802
Shaders: vertex shader, fragment shader
Repository link: https://github.com/congard/algine

Please help... I've already spent about 5 hours trying to figure out what I'm doing wrong

Consider using Debug Output instead of glGetError

https://vallentin.dev/2015/02/23/debugging-opengl

πŸ™‚πŸ™‚πŸ™‚πŸ™‚πŸ™‚<←The tone posse, ready for action.

Advertisement

A couple of other things...

Nvidia drivers accept bad OpenGL calls. Not sure about Intel. Nvidia will try to fix things, kinda like HTML quirks mode (whatever it was called). This isn't a good thing in my opinion.

Also you can use Debug Output (from above) in at least OpenGL 3.3 as long as your card supports 4.3. You don't have to develop in 4.3 to use it as the link I posted would have you believe.

πŸ™‚πŸ™‚πŸ™‚πŸ™‚πŸ™‚<←The tone posse, ready for action.

Thanks for the link! As a result, I received such errors:

Message: glDrawElements has generated an error (GL_INVALID_OPERATION)
Source: API
Type: Error
ID: 1000
Severity: High


Message: glDrawElements failed because the currently active shader combination is invalid (GL_INVALID_OPERATION)
Source: API
Type: Error
ID: 2003
Severity: High

But when compiling the shader, no errors were received. How to understand what the problem is with?

congard said:
But when compiling the shader, no errors were received. How to understand what the problem is with?

I would try again using the Nvidia card with the Debug Output. It may output better error messages. I'll look over the code soon for anything that jumps out, may even get around to compiling. Unfortunately I don't have an AMD GPU.

πŸ™‚πŸ™‚πŸ™‚πŸ™‚πŸ™‚<←The tone posse, ready for action.

Hi. From the documentation of glDrawElements():

GL_INVALID_OPERATION is generated if a geometry shader is active and mode is incompatible with the input primitive type of the geometry shader in the currently installed program object.

GL_INVALID_OPERATION is generated if a non-zero buffer object name is bound to an enabled array or the element array and the buffer object's data store is currently mapped.

Also, glDrawElements() expects a const void * as the last parameter. Not sure if a reinterpret_cast fulfills that. I use (const void *) to offset into an element array for drawing ...

Hope that helps a bit.

Advertisement

Immediately after launching the application on Nvidia, this warning appeared:

Message: Framebuffer detailed info: The driver allocated storage for renderbuffer 1.
Source: API
Type: Other
ID: 131169
Severity: Low

Then after each call to glDrawElements (which is called NOT for drawing in the depth map, but in the "color map") I get the following messages:

Message: Texture state usage warning: Texture 0 is base level inconsistent. Check texture size.
Source: API
Type: Other
ID: 131204
Severity: Low

What are these warnings related to?

Nvidia Nsight didn’t show anything that could cause this problem

Precompiled binaries for Windows: with debug context enabled / debug output and without debug output

I searched on the 2 error messages you posted.

The first error seems to be informative and not really an error.

https://devtalk.nvidia.com/default/topic/848717/opengl/gldebugseverity_low-for-creating-and-attaching-a-renderbuffer-to-an-fbo-/

The second is one I have had before. I don't remember the issue I had but you might try using a different texture. Are you stepping through your code to find where the error occurs?

Unless you are getting obvious graphical errors, I wouldn't worry too much about it. Treat them as you would any 3rd party library warnings. Suppress the messages if they bother you and get back to programming. ;)

πŸ™‚πŸ™‚πŸ™‚πŸ™‚πŸ™‚<←The tone posse, ready for action.

Thanks for your reply!

fleabay said:
Are you stepping through your code to find where the error occurs?

Nvidia warning occurs when called

glDrawElements(GL_TRIANGLES, model.shape->meshes[i].count, GL_UNSIGNED_INT, reinterpret_cast<void*>(model.shape->meshes[i].start * sizeof(uint)))

On AMD, error 1282 (invalid operation) occurs on the same line;
There are no errors/warnings on Intel.
Could the warning that Nvidia gives out be related to the error that AMD is giving?

Later I will post AMD RenderDoc captures and the debug output in AMD CodeXL

This topic is closed to new replies.

Advertisement