GLSL texture2D() always returning black

I’m having a heck of a time getting GLSL texture sampling to work. The two most common reasons I’ve come across in Google searches are not setting minification/magnification filters and mixing up GL_TEXTURE0-based indices with 0-based indices. But I’m not making either of those mistakes.

#include <string.h>

#include <OpenGLES/ES2/gl.h>

#define SHADER_SOURCE(text) "#version 100
" #text


GLubyte textureData[4][320][460];

const char* vertexShaderSource = SHADER_SOURCE(
  attribute vec2 vertexPosition;
  void main() {
    gl_Position = vec4(vertexPosition, 0, 1);
  }
);

const char* fragmentShaderSource = SHADER_SOURCE(
  precision highp float;

  uniform vec2 screenSize;
  uniform sampler2D sampler;
  
  void main() {
    vec2 texCoord = gl_FragCoord.xy / screenSize;
    gl_FragColor = texture2D(sampler, texCoord);
  }
);

const float screenCorners[] = {
  -1.0f, -1.0f,
   1.0f, -1.0f,
   1.0f,  1.0f,
  -1.0f,  1.0f,
};


void drawScene(int screenWidth, int screenHeight) {
  GLuint texture;
  glGenTextures(1, &texture);
  
  glBindTexture(GL_TEXTURE_2D, texture);
  memset(textureData, 0xFF, 4*320*460);
  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, screenWidth, screenHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, textureData);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  glBindTexture(GL_TEXTURE_2D, 0);
  
  //
  
  glEnableVertexAttribArray(0);
  
  GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
  int sourceLength = strlen(vertexShaderSource);
  glShaderSource(vertexShader, 1, &vertexShaderSource, &sourceLength);
  glCompileShader(vertexShader);
  
  GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
  sourceLength = strlen(fragmentShaderSource);
  glShaderSource(fragmentShader, 1, &fragmentShaderSource, &sourceLength);
  glCompileShader(fragmentShader);
  
  GLuint program = glCreateProgram();
  glAttachShader(program, vertexShader);
  glAttachShader(program, fragmentShader);
  glBindAttribLocation(program, 0, "vertexPosition");
  glLinkProgram(program);
  
  GLuint screenSizeUniformLocation = glGetUniformLocation(program, "screenSize");
  GLuint samplersUniformLocation = glGetUniformLocation(program, "sampler");
  
  //
  
  glUseProgram(program);
  glViewport(0, 0, screenWidth, screenHeight);
  
  glActiveTexture(GL_TEXTURE0);
  glBindTexture(GL_TEXTURE_2D, texture);
  
  glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, screenCorners);
  glUniform2f(screenSizeUniformLocation, screenWidth, screenHeight);
  glUniform1i(samplersUniformLocation, 0);
  
  glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
}

I’d expect this code to fill the screen with white pixels, but it’s filling the screen with black. If I replace the fragment shader’s texture2D() call with a constant color, the screen fills with that color as expected. What am I missing?

Try adding the following:

  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

Change GL_CLAMP_TO_EDGE to whatever behavior you want. I had the same problem a while back and specifying the desired behaviour in this regard seamed to fix it.

GL_CLAMP_TO_EDGE seems to make ti work but GL_REPEAT and GL_MIRRORED_REPEAT don’t. I wonder why those don’t work?

GL_REPEAT and GL_MIRRORED_REPEAT only work on power-of-two textures.

Wow, I spent way too much time on this problem. Thanks.

GL_REPEAT and GL_MIRRORED_REPEAT only work on power-of-two textures.

That’s not true at all. They don’t work on rectangle textures, but there’s no problem with using them on 2D NPOTs.

My guess is that he isn’t using opengl at all. He is using opengl es.