Tracking Down a macOS OpenGL Texture Error

While working on my game, I received this cryptic error, along with no textures visible:

UNSUPPORTED (log once): POSSIBLE ISSUE: unit 0 GLD_TEXTURE_INDEX_2D is unloadable and bound to sampler type (Float) – using zero texture because texture unloadable

There are various mentions of this error around the web. Most of them are random peoples’ bug reports that end up being closed without resolution, but there were a few useful resources I came across.

The most referenced one, and probably least relevant to most people, is this post from the Doomsday Engine blog. According to that post, there is a probable bug in Apple’s GLSL compiler, and they had to rewrite a part of their shader to avoid tickling the bug. That’s not hard to believe, but that’s not the problem I had, and probably not most other peoples’ problem either!

A more useful resource was this Apple Developer Forum thread; and specifically, the March 2023 post from “carterd”, who says, in part:

[This error] does appear to be real and not just some garbage being thrown by the M1 GPU. […] This error is thrown whenever the shader does not know where to access texture data. […] Most of the time when I get this error it is because I somehow messed up the coordination of [glUniform1i and glActiveTexture] […]. It can also be called if you didn’t set up your texture correctly (maybe forgot to bind when you were setting up the filter and wrapper or something) […]

This was useful and put me on the right track. I was pretty sure I was binding the texture correctly, and I was, but I looked back at the texture creation code. It appeared right, but I would not be totally surprised if there was a GL error occurring during the creation of the texture that resulted in the texture object not actually pointing to anything, and then hence not being bound correctly later since there would be no texture to bind to.

Adding glGetError calls around, I discovered that it was indeed breaking during texture creation. Specifically, while glTexImage2D succeeded, glGenerateMipmap was failing with a GL_INVALID_OPERATION error. According to the OpenGL ES manual page for glGenerateMipmap, the different ways glGenerateMipmap can cause a GL_INVALID_OPERATION error are:

  • […] if target is GL_TEXTURE_CUBE_MAP and the texture bound to the GL_TEXTURE_CUBE_MAP target of the active texture unit is not cube complete.
  • […] if the levelbase array is stored in a compressed internal format.
  • […] if the levelbase array was not specified with an unsized internal format or a sized internal format that is both color-renderable and texture-filterable.

The texture in question in my application was not a cube map, so the first cause is right out. It was also not using a compressed internal format, so that’s out too. Third one maybe? The internal format I specified was RGB8, format was RGB, and type was UNSIGNED_BYTE. The wording is confusing, but it sounds like what is required is either:

an unsized internal format or a sized internal format that is both color-renderable and texture-filterable.

RGB8 is sized, so that leaves us to determine if it’s color-renderable and texture-filterable. Is it? According to the massive Table 2 “Sized Internal Formats” in the glTexImage2D manual page, it should be! So it should work. Why won’t it?

I regret to inform you that the answer was very stupid. My wrapper around glTexImage2D did all the work of validating the parameters, and then forgot to actually call it. After adding the call that was supposed to be there the whole time, it worked like a charm. 🤦

Tags: ,

Leave a Reply