OpenGL: Lessons learned

Here's a short summary of things I have learned in the last months of OpenGL programming - sometimes the hard way (read: while destroying awful amounts of Club Mate and coffee).

Some of these are rather subtle pitfalls and do not get mentioned in tutorials or books too often.

  • Textures must have one or more mipmaps attached, otherwise they are not considered complete by OpenGL and will not be rendered (or rendered completely black).
  • if you want to re-display what you render into a framebuffer object, use a texture. If you just want to do some processing on the data or use it as the basis for something else - use a renderbuffer.
  • be wary of if-conditionals in GLSL - due to the SIMD architecture of GPUs, even branches which you do not expect to be currently evaluated are actually evaluated in parallel - that might lead to crashes, for example due to unbound texture samplers.
  • when specifying the texture format in glTexImage*D, use a bytesize-specifying format like GL_RGBA8 instead of GL_RGBA - since OpenGL 3.3 some requirements have gotten stronger and not specifying the bytesize is actually not supported anymore and might lead to unexpected results.
  • when using textures in a fragment shader, set the uniform to the texture unit, not the texture ID - for some reason, this is wrong in many code snippets on the internet. One correct way is
  // set the active texture unit 0
  glActiveTexture(GL_TEXTURE0);
  // bind the texture to texture unit 0
  glBindTexture(GL_TEXTURE_2D, myTextureID);
  // tell the fragment shader the texture sits in unit 0
  glUniform1i(glGetUniformLocation(shaderId, "mySamplerUniform"), 0);
  • don't upload geometry data with every frame - in the sense of running glBufferData() in every iteration of the rendering loop. This carries a massive performance penalty of about a factor 5 to 10(!). This generalizes to basically everything: Don't recreate or reupload stuff repeatedly if it's not changing.