GL_TEXTUREn+1 activated and bound instead of GL_TEXTUREn on Apple Silicon M1 (possible bug)

  apple-m1, apple-silicon, c++, opengl, textures

Let’s first acknowledge that OpenGL is deprecated by Apple, that the last supported version is 4.1 and that that’s a shame but hey, we’ve got to move forward somehow and Vulkan is the way :trollface: Now that that’s out of our systems, let’s have a look at this weird bug I found. And let me be clear that I am running this on an Apple Silicon M1, late 2020 MacBook Pro with macOS 11.6. Let’s proceed.

I’ve been following LearnOpenGL and I have published my WiP right here to track my progress. All good until I got to textures. Using one texture was easy enough so I went straight into using more than one, and that’s when I got into trouble. As I understand it, the workflow is more or less

  • load pixel data in a byte array called textureData, plus extra info
  • glGenTextures(1, &textureID)
  • glBindTexture(GL_TEXTURE_2D, textureID)
  • set parameters at will
  • glTexImage2D(GL_TEXTURE_2D, ... , textureData)
  • glGenerateMipmap(GL_TEXTURE_2D) (although this may be optional)

which is what I do around here, and then

  • glUniform1i(glGetUniformLocation(ID, "textureSampler"), textureID)
  • rinse and repeat for the other texture

and then, in the drawing loop, I should have the following:

  • glUseProgram(shaderID)
  • glActiveTexture(GL_TEXTURE0)
  • glBindTexture(GL_TEXTURE_2D, textureID)
  • glActiveTexture(GL_TEXTURE1)
  • glBindTexture(GL_TEXTURE_2D, otherTextureID)

I then prepare my fancy fragment shader as follows:

#version 410 core

out vec4 FragColor;
in vec2 TexCoord;

uniform sampler2D textureSampler;
uniform sampler2D otherTextureSampler;

void main() {
    if (TexCoord.x < 0.5) {
        FragColor = texture(textureSampler, TexCoord);
    } else {
        FragColor = texture(otherTextureSampler, TexCoord);
    }
}

and I should have a quad on screen with a texture made up by textureSampler on its left half, and otherTextureSampler on its right half. Instead, I have otherTextureSampler on the left half, black on the other half, and a log message that says

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

I’ve been on this bug’s trail for two days now and there just isn’t very much on the Internet. Some reports point to a possible bug in Apple’s GLSL compiler, some others point to the need for binding an extra texture for no apparent reason. These three are the most relevant pieces of information I managed to find:

However, none of these helped me very much. Until I did something without thinking. The eagle-eyed among you will have noticed that the drawing code in my git repo is slightly different. It says right here that I am in fact using GL_TEXTURE1 and GL_TEXTURE2.

It was my understanding that 0 and 1 were the two texture units that I was activating and binding, so why does using texture units 1 and 2 yield the expected result?

I tried to add calls to glActiveTexture(GL_TEXTURE0) and 1 right after generating the textures and before binding them, but with zero success. I also tried using a sampler array like this person suggests and going in with a bunch of ifs and integer indices, but of course I was still getting the wrong result.

I spent a few hours trying every possible combination and the only practical "solution" is to use "+1" texture units, as in GL_TEXTUREn with n >= 1.

Question: with all the caveat expressed in the very first paragraph, who is doing something wrong here? Is it noob me who’s trying to learn decades old technology on modern hardware, or is it genuinely a bug in Apple’s implementation of OpenGL or the GLSL compiler, and so there’s zero chance of having it fixed and I should just get on with my "special hardware manufacturer’s" crutches?

Source: Windows Questions C++

LEAVE A COMMENT