OpenGL being very machine specific
Asked Answered
W

1

7

Recently I started using OpenGL in C++ for some 3D rendering, but oddly enough it seems to only work on a few machines. I'm using OpenGL 3.0 or higher (at the moment it is set to 3.0) using vertex array objects (not sure how its called, but the API revision that removed glBegin, glEnd and such).

Before testing it on another machine I always ask for their GPU drivers, most of them support OpenGL 4.2, if not, I make sure they at least support 3.0. Yet on some machines my application simply crashes, or doesn't render anything, OpenGL does not throw any errors (I check errors at least once each frame). It works perfectly fine on my own machine though, and in some cases my machine is even older than some machines on which it doesn't work.

I started using only OpenGL itself and GLEW, but switched to SFML and GLEW for ease of use and some other features I like, OpenGL itself didn't change its behavior though. I did rewrite the engine I was working on at some point to encapsulate all the GL calls and incorporate vertex array objects and some other features, in fact I can give you a list of all the API calls the application uses. Obviously it doesn't use of all of them in the test application, but these are all the calls I use in the engine (this is the bare minimum to be able to render, so yes, the engine is not even near finished):

  • glAttachShader
  • glBindAttribLocation
  • glBindBuffer
  • glBindVertexArray
  • glBufferData
  • glBufferSubData
  • glClear
  • glClearColor
  • glClearDepth
  • glCompileShader
  • glCreateProgram
  • glCreateShader
  • glCullFace
  • glDeleteBuffers
  • glDeleteProgram
  • glDeleteShader
  • glDeleteVertexArrays
  • glDepthFunc
  • glDepthMask
  • glDepthRange
  • glDisableVertexAttribArray
  • glDrawElements
  • glEnable
  • glEnableVertexAttribArray
  • glFrontFace
  • glGenBuffers
  • glGenVertexArrays
  • glGetAttribLocation
  • glGetBufferParameteriv
  • glGetBufferSubData
  • glGetError
  • glGetIntegerv
  • glGetProgramInfoLog
  • glGetProgramiv
  • glGetShaderInfoLog
  • glGetShaderiv
  • glGetShaderSource
  • glGetUniformLocation
  • glIsProgram
  • glIsShader
  • glLinkProgram
  • glMapBufferRange
  • glPixelStorei
  • glShaderSource
  • glUniform(1i, 1ui, 1f, 2f, 3f, 4f, Matrix3fv, Matrix4fv)
  • glUnmapBuffer
  • glUseProgram
  • glVertexAttrib(1i, 1ui, 1f, 2f, 3f, 4f)
  • glVertexAttribPointer

In short, the Shader and ShaderProgram part is nothing special, I have some methods to create/compile them, set some attribute locations beforehand and finally set attributes/uniforms. The buffer objects aren't anything special either, you can write, read and map the buffers, at the moment I'm only using GL_ARRAY_BUFFER and GL_ELEMENT_ARRAY_BUFFER. Finally I'm using vertex array objects to actually render objects, obviously I set attribute pointers, and encapsulated draw calls and program usage, it always uses indexed drawing.

Also, I extensively searched on google and on stack overflow itself for an answer. But all the problems have to do with OpenGL not working anywhere, e.g. some API calls weren't called in order or not at all. Sadly none of these answers work for me, it has always worked on my own machine and other machines I can directly access, but it has never worked when I send the application to someone else to test it on their machine.

Hope this was specific enough XD

EDIT, copy from post down below

Every test is done on either windows vista or 7. I've thrown in an OpenGL error check for about each and every API call, and none seem to catch any error. I'm not able to reproduce it on my own machine, but after some more tracing on other machines I found that it does not crash untill rendering. The setup works fine, it creates all the buffers and objects perfectly fine, but as soon as I try to render a mesh (VAO) it crashes without any errors (well except .exe has stopped working). I suspect the commands glUseProgram or glDrawElements

About an example, unless you want to search through about 10 classes, I can't give you a short example

EDIT, tiny bit of code rendering an object

Mesh class adds these structs to the object so it knows what to draw:

// Define Geometry (draw command)
struct Geometry
{
    // Primitives
    PrimitiveType primitiveType;

    // Indices
    IndexType indexType;
    unsigned int count;  // elements
    unsigned int offset; // bytes
};

Oh, btw, a 'geometry tag' is just a string under which multiple draw calls can be 'put', couple definitions:

// Define a list of primitives
typedef std::vector<Geometry> GeometryList;

// Define Geometry ordered by tag
typedef std::map<const std::string, GeometryList> GeometryMap;

For every 'draw' call it returns a string so the mesh class can bind the appropiate material.

//-----------------------------------------------------------------------
const std::string HardwareObject::nextGeometryTag()
{
    // Loop back
    GeometryMap::const_iterator end = _geometry.end();
    if(_activeGeometry == end)
    {
        // Bind and go to begin
        glBindVertexArray(_GL_VertexArray);
        _activeGeometry = _geometry.begin();
    }

    // Check if new tag exists
    else if(++_activeGeometry == end)
    {
        // Unbind and return empty tag
        glBindVertexArray(0);
        return "";
    }
    return _activeGeometry->first;
}

//-----------------------------------------------------------------------
bool HardwareObject::drawGeometryTag() const
{
    // Validate current tag
    if(_activeGeometry == _geometry.end()) return false;

    // Draw each geometry call of tag
    for(GeometryList::const_iterator it = _activeGeometry->second.begin(); it != _activeGeometry->second.end(); ++it)
        glDrawElements(it->primitiveType, it->count, it->indexType, (void*)it->offset);

    // GL Error
    return !Console::GET().getError("HardwareObject Drawing");
}

//-----------------------------------------------------------------------
void HardwareObject::resetGeometryTag()
{
    _activeGeometry = _geometry.end();
}

EDIT, the mesh calling all the above methods to actually render the object

the lockVertexAttributes() just makes sure all the attribute pointers are bound to the correct vertex buffer. The bind method of the HardwareProgram does nothing more than checking if the programs is compiled and calling glUseProgram

//-----------------------------------------------------------------------
bool Mesh::render()
{
    // Lock vertex attributes
    if(!lockVertexAttributes()) return false;

    // To avoid errors
    _object.resetGeometryTag();

    // Loop while there's a tag
    for(std::string tag = _object.nextGeometryTag(); tag != ""; tag = _object.nextGeometryTag())
    {
        // Find material
        MaterialMap::const_iterator it = _materials.find(tag);
        if(it == _materials.end()) continue;

        // Bind material (get program directly)
        const HardwareProgram *prog = it->second->getProgram();
        if(!prog) continue;
        if(!prog->bind()) continue;

        // Draw tag
        _object.drawGeometryTag();
    }

    // Ok!
    return true;
}
Wade answered 1/8, 2012 at 11:3 Comment(8)
Did you debug your program? Where exactly does it crash? On which plattform? Can you reproduce this behavior with a simple, short example?Arium
I suspect this is really hard, if not impossible, to answer without a reproducible short example.Exactly
Every test is done on either windows vista or 7. I've thrown in an OpenGL error check for about each and every API call, and none seem to catch any error. I'm not able to reproduce it on my own machine, but after some more tracing on other machines I found that it does not crash untill rendering. The setup works fine, it creates all the buffers and objects perfectly fine, but as soon as I try to render a mesh (VAO) it crashes without any errors (well except .exe has stopped working). I suspect the commands glUseProgram or glDrawElementsWade
Do you 'encapsulate' your GL_ELEMENT_ARRAY_BUFFER binding in your VAO ?Skerry
Could you post at least the code for your draw function, i.e. the one calling glDrawElements or equivalent.Skerry
yes, as soon as you create a mesh object, it creates the VAO and binds the index buffer to the VAO, it also makes sure all the attribute pointers are bound to the GL_ARRAY_BUFFER before renderingWade
@rotoglup, see the question, added all the rendering code, if you need anything else, just shoutWade
one last thing, the title of your question is not so much related to your problem. You may find it helpful to attract attention for your next questions to have a more specific title, closely related to the question you're asking.Skerry
S
5

My bet would be that you're binding the GL_ELEMENT_ARRAY_BUFFER through your VAO.

I've had issues in the past (a few years back) with this on certain versions of NVidia drivers (I don't have any record of which version(s) though), where this purely crashed the application.

My workaround at the time was to rely on VAO to set GL_ARRAY_BUFFER binding and vertex attrib pointers, but I explicity redefined the GL_ELEMENT_ARRAY_BUFFER binding after the glBindVertexArray.

I think the problem is now solved, but some old drivers around may exhibit the problem.

Can you see a pattern for the configuration of platforms that have the problem ?

Skerry answered 1/8, 2012 at 18:57 Comment(1)
That actually solved the problem, thanks for your help! Till now I've only had the chance to test it on one machine on which it didn't work before, and as you said, it uses an NVidia card, as soon as I get my hands on the other machines, I'll try it there. To be exact: geforce.com/hardware/notebook-gpus/geforce-gt-540m/…Wade

© 2022 - 2024 — McMap. All rights reserved.