GL Crash on random PC's

I have an application that crashes for only a small percentage of users. Even crashing on 3000 and 4000 series RTX cards.

I finally cut down my program to have a boot that immediately creates a square and renders it before anything else and yet it still is crashing every time on the first draw call. Anyone see anything wrong? My mind is blown. I’m a 20+ year game developer and rendering engineer. Never seen this and I don’t have access to the hardware to debug and try things repeatedly.


                CreateOpenGLWindow();
                glewInit();

                glBindVertexArray(0);
		m_spriteMesh = new Mesh();
		m_spriteMesh->material.shader = gl.m_shaders["Texture2D"];
		m_spriteMesh->num_verts = 4;
		m_spriteMesh->num_faces = 2;
		Vertex* vertex = new Vertex(); 
                      vertex->position = Vec3(-1, -1, 0); 
                      vertex->texCoords.push_back(new Vec2(0, 0)); 
                     m_spriteMesh->verts.push_back(vertex);
	        vertex = new Vertex(); 
                     vertex->position = Vec3(1, -1, 0); 
                     vertex->texCoords.push_back(new Vec2(1, 0)); 
                      m_spriteMesh->verts.push_back(vertex);
		vertex = new Vertex(); 
                     vertex->position = Vec3(1, 1, 0); 
                     vertex->texCoords.push_back(new Vec2(1, 1)); 
                     m_spriteMesh->verts.push_back(vertex);
		vertex = new Vertex(); 
                    vertex->position = Vec3(-1, 1, 0); 
                   vertex->texCoords.push_back(new Vec2(0, 1)); 
                    m_spriteMesh->verts.push_back(vertex);

		Face* face = new Face();
		    face->indices[0] = 0; face->indices[1] = 1; face->indices[2] = 2;
		    m_spriteMesh->faces.push_back(face);
		face = new Face();
		  face->indices[0] = 2; face->indices[1] = 3; face->indices[2] = 0;
		  m_spriteMesh->faces.push_back(face);


		float* verticesCache_ = new float[m_spriteMesh->num_verts * 3];
		float* texcoordsCache_ = new float[m_spriteMesh->num_verts * 2];
		unsigned int* indicesCache_ = new unsigned int[m_spriteMesh->num_faces * 3];

		int vertex_counter = 0;

		for (int i = 0; i < m_spriteMesh->num_verts; i++)
		{
			Vertex* vert = m_spriteMesh->verts[vertex_counter];
			m_spriteMesh->verticesCache_[vertex_counter * 3] = vert->position.x;
			m_spriteMesh->verticesCache_[vertex_counter * 3 + 1] = vert->position.y;
			m_spriteMesh->verticesCache_[vertex_counter * 3 + 2] = vert->position.z;

			
			if (vert->texCoords.size() != 0)
			{
				m_spriteMesh->texcoordsCache_[vertex_counter * 2] = vert->texCoords[0]->x;
				m_spriteMesh->texcoordsCache_[vertex_counter * 2 + 1] = vert->texCoords[0]->y;
			}

			vertex_counter++;
		}

		

		unsigned int offsetFromVBOStart;
		int vertexDataSize = (3 + 2)*4;//pos and texcoord, 4 bytes float
		unsigned int size_of_buffer = m_spriteMesh->num_verts * vertexDataSize;
		glGenBuffers(1, &vboIndex);
	        glBindBuffer(GL_ARRAY_BUFFER, vboIndex);
	        glBufferData(GL_ARRAY_BUFFER, size_of_buffer , NULL, GL_STATIC_DRAW);

		GLintptr writePointer = 0;
		m_vboLayout.positionDataOffset = writePointer;
		glBufferSubData(GL_ARRAY_BUFFER, writePointer, sizeof(GLfloat) * m_spriteMesh->num_verts*3, m_spriteMesh->verticesCache_);
		writePointer += sizeof(GLfloat) * m_spriteMesh->num_verts * 3;

		m_vboLayout.texCoordOffsets[0] = writePointer;
		glBufferSubData(GL_ARRAY_BUFFER, writePointer, sizeof(GLfloat) * m_spriteMesh->num_verts * 2, m_spriteMesh->texcoordsCache_);
		writePointer += sizeof(GLfloat) * m_spriteMesh->num_verts * 2;

		for (int i = 0; i < m_spriteMesh->faces.size(); i++)
		{
			m_spriteMesh->indicesCache_[i * 3] = m_spriteMesh->faces[i]->indices[0];
			m_spriteMesh->indicesCache_[i * 3 + 1] = m_spriteMesh->faces[i]->indices[1];
			m_spriteMesh->indicesCache_[i * 3 + 2] = m_spriteMesh->faces[i]->indices[2];
		}

		//Indices
		glGenBuffers(1, &m_spriteMesh->VBO_Index_Indices);
		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_spriteMesh->VBO_Index_Indices);
		gl.GLDetectError();
		glBufferData(GL_ELEMENT_ARRAY_BUFFER, m_spriteMesh->num_faces * 3 * sizeof(GL_UNSIGNED_INT), m_spriteMesh->indicesCache_, GL_STATIC_DRAW);
		


		glGenVertexArrays(1, &m_spriteMesh->VAO_Index);
		glBindVertexArray(m_spriteMesh->VAO_Index);
		glBindBuffer(GL_ARRAY_BUFFER, m_spriteMesh->VBO_Index);
		glEnableVertexAttribArray(0);
		glEnableVertexAttribArray(1);
		glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)m_spriteMesh->m_vboLayout.positionDataOffset);
		glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, (void*)m_spriteMesh->m_vboLayout.texCoordOffsets[0]);

		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_spriteMesh->VBO_Index_Indices);

		glBindVertexArray(0);

	}


                glUseProgram(spriteShader->handle);
		spriteShader->sendUniform("invertTexCoord", 0);
		Matrix4 orthoMatrix;
		Matrix4 viewMatrix;
		Matrix4 modelMatrix;
		modelMatrix.LoadIdentity();
		modelMatrix.Set_Scale_Matrix(.5,.5,.5);
		modelMatrix.Set_Translation(Vec3(0,0,-1));
		orthoMatrix.glOrtho(-1, 1, -1, 1, 0, 100);
		viewMatrix.LoadIdentity();
		spriteShader->sendUniformAnimationMatrixBuffer("glProjectionMatrix", &(orthoMatrix.data[0][0]), 1);
		spriteShader->sendUniformAnimationMatrixBuffer("ViewMatrix", &(viewMatrix.data[0][0]), 1);
		spriteShader->sendUniformAnimationMatrixBuffer("modelMatrix", &(modelMatrix.data[0][0]), 1);
		spriteShader->sendUniform("ColorModulate", 1.0f, 1.0f, 1.0f, 1.0f);
		spriteShader->sendUniform("Tex", 0);

		gl.GLBindTexture(GL_TEXTURE_2D, 0, Main_Level->Find_Texture("whiteSquare.jpg")->GL_Texture_Index);

		glBindVertexArray(SpriteMesh->VAO_Index);
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
>>>>>>>>glDrawElements(GL_TRIANGLES, this->num_faces*3, GL_UNSIGNED_INT, 0);





	


Vertex Shader
layout (location = 0) in vec3 glVertex;
layout (location = 1) in vec2 glMultiTexCoord0;

uniform mat4 modelMatrix;

uniform mat4 glProjectionMatrix;
uniform mat4 ViewMatrix;
uniform bool invertTexCoord = false;

out vec2 glTexCoord0;

void main()
{
	vec4 glVertex4 = vec4(glVertex, 1.0);
	mat4 glModelViewMatrix = ViewMatrix*modelMatrix;
	vec3 posCamera = (glModelViewMatrix*glVertex4).xyz;
	
	glTexCoord0 = glMultiTexCoord0;
	if(invertTexCoord)
	{
		glTexCoord0.y *= -1.0;
	}
	
	gl_Position = glProjectionMatrix*vec4(posCamera,1);
}


Fragment Shader 
layout (location = 0) out vec4 glFragData0;

uniform sampler2D Tex;
uniform vec4 ColorModulate;

in vec2 glTexCoord0;

void main()
{
	vec4 texColor = texture(Tex, glTexCoord0);
	if(texColor.a < 0.0039)
	{
		discard;
	}
	glFragData0 = texColor*ColorModulate;
}

I would not try to debug anything without using glDebugMessageCallback.

Yea I have it on. Zero errors on any of my computers. This works on such a wide range at home from $100 beelinks up to RTX 5060 and a bunch in between. I already ran RenderDoc and NSight. No issues. Ran GLIntercept to validate there were no other calls being made somewhere.

Windows?

If so, in your app, install a crash callback with SetUnhandledExceptionFilter(). In this handler, call MiniDumpWriteDump() with the DumpType = MiniDumpWithFullMemory, saving this to a disk file. Build your app with full Debug info including PDBs, and ideally with all compiler optimization disabled (though if that doesn’t crash, enable basic optimizations). Have a crashing user run this version and send you the crash dump. Load into MSVS and inspect.

This will give you all threads, thread stacks, point of crash, and CPU memory state, so you can go inspect variables for clues as to what the heck is going wrong.

Also, if you can get a crashing user that’s running NVIDIA GPU + NVIDIA drivers to do this test, initially have them do this:

  • NVIDIA Control Panel → Manage 3D Settings → Threaded optimization = OFF

With this OFF, if you crash deep in the bowels of GL, you should be able to see the full call stack through the GL call in your app code that is indirectly triggering the crash. Moreover, this is useful if you’ve installed a glDebugMessageCallback() to get the GL driver to call you if/when it detects an error, as this callback will be kicked in the exact callstack and within the specific GL call your app code made that triggered this error. This behavior makes debugging GL errors instigated by your app’s code “really” easy.

“if you crash deep in the bowels of GL, you should be able to see the full call stack through the GL call in your app code that is indirectly triggering the crash.”

I’ll try. Right now I write to a console window as well as a txt file after each line of code. (I close the file after every write so that its up to date). I already know it never completes the first glDrawElements call. Will the thread optimization get me any actual information from within the glDrawElements call?

I’m currently testing out some things someone suggested elsewhere because I ‘glBindVertexArray(0)’ quite a bit to make sure I wouldn’t ever be messing up prior bound vertex arrays. Looking into if this is an issue that messes things up, even if I later bind a proper VAO.

No. But with it OFF, it will get that GL call on the stack in your app thread. With it ON, the crash may be in a driver thread you don’t have visibility into.

That said, if you store your draw call parms into vars before the draw call and build without optimization, you’ll be able to inspect those vars’ values in the mini dump.

@dpadam450 what happened? Did you find the root cause or a workaround?

I have no idea still. I’d need to get my hands on broken hardware to figure it out. I have more 5 more customers since this post and it works just fine on all their computers.

Dear @dpadam450

Crashes like this usually mean the GPU doesn’t have the right state set up. The safest pattern is:

  1. Create your VAO and bind it.
  2. Bind your VBOs and call glVertexAttribPointer while the VAO is bound.
  3. Bind your EBO while the VAO is bound (this “sticks” to the VAO).
  4. Don’t unbind the VAO before drawing — just call glDrawElements.

Also make sure your attribute sizes match the shader (e.g. vec3 → 3 floats).

If you want to double‑check, add a debug callback so OpenGL prints errors:

glEnable(GL_DEBUG_OUTPUT); glDebugMessageCallback(myCallback, nullptr);

That way you’ll see what’s wrong instead of a silent crash.

GL;HC;

~p3nGu1nZz

I haven’t looked at it in a while. More people have verified working PC’s. I cleaned up all the code for strictness. I have debug output. I tried RenderDoc/Nvidia NSight. Nothing complained. Eventually may get back to it.

1 Like