c++openglnvidiaopengl-3depth-testing

OpenGL: Radeon driver seems to mess with depth testing


I'm having a really weird issue with depth testing here. I'm rendering a simple mesh in an OpenGL 3.3 core profile context on Windows, with depth testing enabled and glDepthFunc set to GL_LESS. On my machine (a laptop with a nVidia Geforce GTX 660M), everything is working as expected, the depth test is working, this is what it looks like:

enter image description here

Now, if I run the program on a different PC, a tower with a Radeon R9 280, it looks more like this:

enter image description here

Strange enough, the really weird thing is that when I call glEnable(GL_DEPTH_TEST) every frame before drawing, the result is correct on both machines. As it's working when I do that, I figure the depth buffer is correctly created on both machines, it just seems that the depth test is somehow being disabled before rendering when I enable it only once at initialization. Here's the minimum code that could somehow be part of the problem:

Code called at initialization, after a context is created and made current:

glEnable(GL_CULL_FACE);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);

Code called every frame before the buffer swap:

glClearColor(0.4f, 0.6f, 0.8f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

// mShaderProgram->getID() simply returns the handle of a simple shader program
glUseProgram(mShaderProgram->getID());  

glm::vec3 myColor = glm::vec3(0.7f, 0.5f, 0.4f);
GLuint colorLocation = glGetUniformLocation(mShaderProgram->getID(), "uColor");
glUniform3fv(colorLocation, 1, glm::value_ptr(myColor));

glm::mat4 modelMatrix = glm::mat4(1.0f);
glm::mat4 viewMatrix = glm::lookAt(glm::vec3(0.0f, 3.0f, 5.0f), glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 1.0f, 0.0f));
glm::mat4 projectionMatrix = glm::perspectiveFov(60.0f, (float)mWindow->getProperties().width, (float)mWindow->getProperties().height, 1.0f, 100.0f);
glm::mat4 inverseTransposeMVMatrix = glm::inverseTranspose(viewMatrix*modelMatrix);

GLuint mMatrixLocation = glGetUniformLocation(mShaderProgram->getID(), "uModelMatrix");
GLuint vMatrixLocation = glGetUniformLocation(mShaderProgram->getID(), "uViewMatrix");
GLuint pMatrixLocation = glGetUniformLocation(mShaderProgram->getID(), "uProjectionMatrix");
GLuint itmvMatrixLocation = glGetUniformLocation(mShaderProgram->getID(), "uInverseTransposeMVMatrix");

glUniformMatrix4fv(mMatrixLocation, 1, GL_FALSE, glm::value_ptr(modelMatrix));
glUniformMatrix4fv(vMatrixLocation, 1, GL_FALSE, glm::value_ptr(viewMatrix));
glUniformMatrix4fv(pMatrixLocation, 1, GL_FALSE, glm::value_ptr(projectionMatrix));
glUniformMatrix4fv(itmvMatrixLocation, 1, GL_FALSE, glm::value_ptr(inverseTransposeMVMatrix));

// Similiar to the shader program, mMesh.gl_vaoID is simply the handle of a vertex array object
glBindVertexArray(mMesh.gl_vaoID);

glDrawArrays(GL_TRIANGLES, 0, mMesh.faces.size()*3);

With the above code, I'll get the wrong output on the Radeon. Note: I'm using GLFW3 for context creation and GLEW for the function pointers (and obviously GLM for the math). The vertex array object contains three attribute array buffers, for positions, uv coordinates and normals. Each of these should be correctly configured and send to the shaders, as everything is working fine when enabling the depth test every frame.

I should also mention that the Radeon machine runs Windows 8 while the nVidia machine runs Windows 7.

Edit: By request, here's the code used to load the mesh and create the attribute data. I do not create any element buffer objects as I am not using element draw calls.

std::vector<glm::vec3> positionData;
std::vector<glm::vec2> uvData;
std::vector<glm::vec3> normalData;
std::vector<meshFaceIndex> faces;

std::ifstream fileStream(path);
if (!fileStream.is_open()){
    std::cerr << "ERROR: Could not open file '" << path << "!\n";
    return;
}
std::string lineBuffer;
while (std::getline(fileStream, lineBuffer)){
    std::stringstream lineStream(lineBuffer);
    std::string typeString;
    lineStream >> typeString;   // Get line token
    if (typeString == TOKEN_VPOS){  // Position
        glm::vec3 pos;
        lineStream >> pos.x >> pos.y >> pos.z;
        positionData.push_back(pos);
    }
    else{
        if (typeString == TOKEN_VUV){   // UV coord
            glm::vec2 UV;
            lineStream >> UV.x >> UV.y;
            uvData.push_back(UV);
        }
        else{
            if (typeString == TOKEN_VNORMAL){   // Normal
                glm::vec3 normal;
                lineStream >> normal.x >> normal.y >> normal.z;
                normalData.push_back(normal);
            }
            else{
                if (typeString == TOKEN_FACE){  // Face
                    meshFaceIndex faceIndex;
                    char interrupt;
                    for (int i = 0; i < 3; ++i){
                        lineStream >> faceIndex.positionIndex[i] >> interrupt
                            >> faceIndex.uvIndex[i] >> interrupt
                            >> faceIndex.normalIndex[i];
                    }
                    faces.push_back(faceIndex);
                }
            }
        }
    }
}
fileStream.close();     

std::vector<glm::vec3> packedPositions;
std::vector<glm::vec2> packedUVs;
std::vector<glm::vec3> packedNormals;

for (auto f : faces){
    Face face;  // Derp derp;
    for (auto i = 0; i < 3; ++i){
        if (!positionData.empty()){
            face.vertices[i].position = positionData[f.positionIndex[i] - 1];
            packedPositions.push_back(face.vertices[i].position);
        }
        else
            face.vertices[i].position = glm::vec3(0.0f);
        if (!uvData.empty()){
            face.vertices[i].uv = uvData[f.uvIndex[i] - 1];
            packedUVs.push_back(face.vertices[i].uv);
        }
        else
            face.vertices[i].uv = glm::vec2(0.0f);
        if (!normalData.empty()){
            face.vertices[i].normal = normalData[f.normalIndex[i] - 1];
            packedNormals.push_back(face.vertices[i].normal);
        }
        else
            face.vertices[i].normal = glm::vec3(0.0f);
    }
    myMesh.faces.push_back(face);
}

glGenVertexArrays(1, &(myMesh.gl_vaoID));
glBindVertexArray(myMesh.gl_vaoID);

GLuint positionBuffer;  // positions
glGenBuffers(1, &positionBuffer);
glBindBuffer(GL_ARRAY_BUFFER, positionBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(glm::vec3)*packedPositions.size(), &packedPositions[0], GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);

GLuint uvBuffer;    // uvs
glGenBuffers(1, &uvBuffer);
glBindBuffer(GL_ARRAY_BUFFER, uvBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(glm::vec2)*packedUVs.size(), &packedUVs[0], GL_STATIC_DRAW);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, (void*)0);

GLuint normalBuffer;    // normals
glGenBuffers(1, &normalBuffer);
glBindBuffer(GL_ARRAY_BUFFER, normalBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(glm::vec3)*packedNormals.size(), &packedNormals[0], GL_STATIC_DRAW);
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);


glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);

The .obj loading routine is mostly adapted from this one: http://www.limegarden.net/2010/03/02/wavefront-obj-mesh-loader/


Solution

  • This doesn't look like a depth testing issue to me, but more like misalignment in the vertex / index array data. Please show us the code in which you load the vertex buffer objects and the element buffer objects.