Why does glVertexAttribPointer/glDrawArrays crash here (only with certain drivers/GPUs)?
-
I wrote a simple OpenGL program with Qt and it runs fine on my PC with a Nvidia graphics card but crashes on my laptop with Intel HD graphics 4400 (0xc0000005 read access violation by the way). The problem is the
glVertexAttribPointer
call. If I uncomment this call (or theglDrawArrays
orglEnableVertexAttribArray
call of course) the program runs without crash. Did I do something wrong or is this a driver issue? It may just be a stupid mistake on my side but I don't get why this works perfectly fine on my PC. I use Windows 8.1 on both systems.(It is exactly the same project on both computers, the same executable and recompiling on the laptop doesn't solve the error. I installed the latest HD graphics drivers. It's the same no matter what OpenGL context I request - I tried 3.3 core, 4.2 core and 4.2 compatibility - in all cases the context creates and initializes successfully but then crashes at the glDrawArrays call)
EDIT: Here are links to the source files so you can download them directly and try it out:
openglwindow.h https://docs.google.com/file/d/0B8VtjZLH6qioVEhmYXM0eGJQRXM/edit?usp=docslist_api
openglwindow.cpp https://docs.google.com/file/d/0B8VtjZLH6qioOGc5Y21ORzBZV0U/edit?usp=docslist_api
main.cpp https://docs.google.com/file/d/0B8VtjZLH6qioa2pBSDNzcGl2WGM/edit?usp=docslist_apiThe render code:
@ void OpenGLWindow::render()
{
static const GLfloat colorBg[] = {1.0f, 0.0f, 0.0f, 1.0f};
glClearBufferfv(GL_COLOR, 0, colorBg);static GLfloat const triangleVertices[] = { 0.8f, 0.8f, 0.0f, 1.0f, 0.8f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f }; static const int vertexLocation = glGetAttribLocation(m_program.programId(), "vertex"); glEnableVertexAttribArray(vertexLocation); glVertexAttribPointer(vertexLocation, 4, GL_FLOAT, GL_FALSE, 0, triangleVertices); glDrawArrays(GL_TRIANGLES, 0, 3); glDisableVertexAttribArray(vertexLocation); }@
The value of
vertexLocation
is 0 which is correct, I tried using a fixed location withlayout (location=0)
before and it resulted in the same crash. These are the only OpenGL commands as I created a new project and reduced the code to the absolute minimum to reproduce the error.glVertexAttrib4fv
works correctly by the way. And hard coding the coordinates in the shader and passing for example a color viaglVertexAttrib4fv
works and draws the triangle correctly.The initialization method with shader code:
@ void OpenGLWindow::initialize()
{
glViewport(0, 0, width(), height());m_program.addShaderFromSourceCode(QOpenGLShader::Vertex, "#version 330 core\n" "in vec4 vertex;\n" "void main(void)\n" "{\n" " gl_Position = vertex;\n" "}"); m_program.addShaderFromSourceCode(QOpenGLShader::Fragment, "#version 330 core\n" "out vec4 color;\n" "void main(void)\n" "{\n" " color = vec4(0.0f, 0.8f, 0.0f, 1.0f);\n" "}"); m_program.link(); m_program.bind(); static QOpenGLVertexArrayObject vao; vao.create(); vao.bind(); }@
-
in yout glVertexAttribPointer you are passing as an offset pointer the pointer to your data itself, try to put it as a null or 0
-
But how do I pass the data to the shader then? I read many examples that show that this code is supposed to be working and as I said it works on my Nvidia card.
-
as far as I am aware the glVertexAttribPointer
is a description of the data , not the data itself.
for example if I have to send the data every render loop i do this@//Bind to buffer
glBindBuffer(GL_ARRAY_BUFFER, vbo);
//copy the data on the gpu
glBufferData(GL_ARRAY_BUFFER, m_positions.size()*sizeof(float),
&m_positions[0], GL_STATIC_DRAW);
//enable corresponding attribute
glEnableVertexAttribArray(0);
//describe the data (in this case a vector array each vertex is composed of 4 values)
glVertexAttribPointer(0,4,GL_FLOAT,GL_FALSE,0,0);
glEnable(GL_PROGRAM_POINT_SIZE);
//draw array
glDrawArrays(GL_POINTS, 0, m_positions.size());@instead if dont need to copy the data because did not change i just skip the glBufferData step
-
Ok, yeah. Using a buffer is of course an alternative. Thanks.
But I'm still wondering why this works only on my home PC graphics card. Also exactly this way is shown in the official documentation of QOpenGLShaderProgram (http://qt-project.org/doc/qt-5/qopenglshaderprogram.html) - it just uses the qt equivalents of the methods like setAttributeArray which leads to the same crash.
-
mmmm not sure if it s a shader program , where do you send the data on gpu?
anyway the problem might be that some driver are more forgiving then other maybe? I am working with qt and opengl on diferent hardware and did not have many problems.
-
I don't know if you can call this forgiving. Interpreting an offset as an absolute pointer (what the desktop Nvidia driver apparently does) seems like something completely different...
Anyway this code still crashes which uses the same methods in the same order as the example in the documentation I referred to above:
(m_program refers to my QOpenGLShaderProgram from the initialization in my first post)
@void OpenGLWindow::render()
{
static const GLfloat colorBg[] = {1.0f, 0.0f, 0.0f, 1.0f};
glClearBufferfv(GL_COLOR, 0, colorBg);static GLfloat const triangleVertices[] = { 0.8f, 0.8f, 0.0f, 1.0f, 0.8f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f }; static const int vertexLocation = m_program.attributeLocation("vertex"); m_program.enableAttributeArray(vertexLocation); m_program.setAttributeArray(vertexLocation, triangleVertices, 4); glDrawArrays(GL_TRIANGLES, 0, 3); m_program.disableAttributeArray(vertexLocation);
}@
-
mmmm what if you try :
glDrawArrays(GL_TRIANGLES, 0, 1); ? -
It still crashes. It doesn't even draw a point when I change to GL_POINTS as it crashes at the vertex fetching stage. Of course I can use setAtrributeValue in this simple case but then I can't pass vertex data for multiple vertices to the shader. The second alternative is using a buffer like you suggested but then I don't get why this setAttributeArray method exists if it doesn't work consistently. Again this code works on my desktop GPU without a problem but I just had the chance to try it on a workstation at my job which uses a Nvidia NVS300 card with a Quadra/NVS driver and it also crashes.
-
mmmmm that s weird then all my guesses expired, try to do that with the buffer if it solve the problem if so we can assume is a qt problem and maybe you can flag it as a bug.
If not then it might be something driver related? -
Ok. I get why using the Qt SetAttributeArray method also crashes. I had a look in the source of the QOpenGLShaderProgram and it does nothing else than calling the glVertexAttribPointer OpenGL method I used in my first example.
@void QOpenGLShaderProgram::setAttributeArray (int location, const GLfloat *values, int tupleSize, int stride)
{
Q_D(QOpenGLShaderProgram);
Q_UNUSED(d);
if (location != -1) {
d->glfuncs->glVertexAttribPointer(location, tupleSize, GL_FLOAT, GL_FALSE, stride, values);
}@So I guess either it is ok to use glVertexAttribPointer in this way and it's a driver bug or it is not ok to do this and Qt should drop these methods (or implement them using a buffer) and therefore it's a bug in Qt.
Somebody with a bit more OpenGL experience should be able to answer this problem... Do you think I should open a bug ticket for Qt and let them decide on which side the problem is? -
I was reading around of other people having trouble with intel grapichs and opengl. Do you have a discrete card on your laptop to switch on and see if keeps crasing ?
Yes might be worth to flag it to the qt guys
-
I was just able to test the code on a workstation at my job with a Nvidia (Quadro) NVS300 graphics card that of course uses a Qudrao driver instead of the GeForce driver and it also crashed. But I changed some things in the code between testing it at home and at the workstation to see whether it fixes the problem on my laptop. So I'll wait reporting this issue until I verified that it still works at home and I didn't mess up something else. (But this is highly unlikely because it's still nearly exactly the same code as the example in the Qt documentation shows)
-
Keep me posted man I am quite curious now tx
-
I'll do so! Maybe the OpenGL glVertexAttribPointer method is really not intended to be used in this way (all the books just describe the pointer to be an offset inside of an user created buffer). So the programmers of Qt might just got it wrong like I did and never noticed because some drivers accept it...
-
It still works correctly on my home PC. I reported the problem here: https://bugreports.qt-project.org/browse/QTBUG-40150
-
I got the same problem. I solved it by using this invocation ordering:
setAttributeArray(0,...);
enableAttributeArray(0);
glDrawArrays();
disableAttributeArray(0);It worked. I do this for every object I draw.
Regards. -
I got the same problem. I solved it by using this invocation ordering:
setAttributeArray(0,...);
enableAttributeArray(0);
glDrawArrays();
disableAttributeArray(0);It worked. I do this for every object I draw.
Regards.