GTexSubImage2D won't draw on screen

#1

I’m trying to render an YUV frame using OpenGL. I’m trying for hours to find the problem but I can’t see what I did wrong. I see a green screen (because the YUV matrix converts black, which is 0,0,0 to green because there’s no initial data). If I uncomment //FragColor = vec4(1.0,0,0, 1.0);, I see a red screen, which confirms the fragment shader is working.

As you can see, I have 3 texture units, one for Y, other for U and other for V and I activate each one by tex_y, tex_u, tex_v uniform samplers.

Vertex shader:

        #version 330 core
        layout (location = 0) in vec3 aPos;
        layout (location = 1) in vec2 aTexCoord;
        
        out vec2 TexCoord;
        
        void main()
        {
            gl_Position = vec4(aPos, 1.0);
            TexCoord = vec2(aTexCoord.x, aTexCoord.y);
        }

Fragment shader:

        #version 330 core
        out vec4 FragColor;
        
        in vec2 TexCoord;
        
        uniform sampler2D tex_y;
        uniform sampler2D tex_u;
        uniform sampler2D tex_v;
        
        void main(void)tex_v
        {
        	vec3 yuv;
        	vec3 rgb;
        	yuv.x = texture(tex_y, TexCoord).r;
        	yuv.y = texture(tex_u, TexCoord).r - 0.5;
        	yuv.z = texture(tex_v, TexCoord).r - 0.5;
        	rgb = mat3(1.0, 1.0, 1.0,
        		0.0, -0.39465, 2.03211,
        		1.13983, -0.58060, 0.0) * yuv;
        	FragColor = vec4(rgb, 1.0);
        	//FragColor = vec4(1.0,0,0, 1.0);
        }

Here’s the rendering code:

        if (firstRun) {    
    	    const GLfloat vertices_textures[20] = {
    	    //vertices            //positions
    	    -1.0f, -1.0f, 0.0f,    0.0f, 1.0f,
    	    1.0f, -1.0f, 0.0f,     1.0f, 1.0f,
    	    -1.0f, 1.0f, 0.0f,     0.0f, 0.0f,
    	    1.0f, 1.0f, 0.0f,      1.0f, 0.0f
    	    };
    	    
    	    program = std::make_unique<Program>();
    	    program->attach_shader(Shader(ShaderType::Vertex, "video.vert"));
    	    program->attach_shader(Shader(ShaderType::Fragment, "yuv420p.frag"));
    	    
    	    program->link();
    	    
    	    vextexInLocation = glGetAttribLocation(program->get_id(), "aPos");
    	    textureInLocation = glGetAttribLocation(program->get_id(), "aTexCoord");
    	    
    	    glGenVertexArrays(1, &VAO);
    	    glGenBuffers(1, &VBO);
    	    
    	    glBindVertexArray(VAO);
    	    
    	    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    	    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices_textures), vertices_textures, GL_STATIC_DRAW);
    	    
    	    glVertexAttribPointer(vextexInLocation, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (void *)0);
    	    glEnableVertexAttribArray(vextexInLocation);
    	    
    	    glVertexAttribPointer(textureInLocation, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (void*)(3 * sizeof(GLfloat)));
    	    glEnableVertexAttribArray(textureInLocation);
    	    
    	    
    	    textureLocation[0] = glGetUniformLocation(program->get_id(), "tex_y");
    	    textureLocation[1] = glGetUniformLocation(program->get_id(), "tex_u");
    	    textureLocation[2] = glGetUniformLocation(program->get_id(), "tex_v");
        
        	glGenTextures(3, textureId);
        	for (int i = 0; i < 3; i++)
        	{
        
        		glBindTexture(GL_TEXTURE_2D, textureId[i]);
        		
        		glTexImage2D(GL_TEXTURE_2D,
        					 0,
        					 GL_LUMINANCE,
        					 width,
        					 height,
        					 0,
        					 GL_LUMINANCE,
        					 GL_UNSIGNED_BYTE,
        					 NULL);
        		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        	}
            firstRun = false;
        }
        
        program->use();
        
        for (int j = 0; j < 3; j++)
        {
        	glActiveTexture(GL_TEXTURE0 + j);
        	glBindTexture(GL_TEXTURE_2D, textureId[j]);
        	
        	glTexSubImage2D(GL_TEXTURE_2D,
        			0,
        			0,
        			0,
        			width,
        			height,
        			GL_LUMINANCE,
        			GL_UNSIGNED_BYTE,
        			frame->buffer[j]);
        	
        	glUniform1i(textureLocation[j], j);
        
        }
        
        glBindVertexArray(VAO);
        glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
#2

From the symptoms, I’m guessing that all of the texture() calls are returning zeros.

  • Have you checked for errors?
  • Does frame->buffer[] contain valid data?
  • Are the U/V channels biased or signed (although a mismatch here shouldn’t result in a solid colour)?
  • Try rendering the YUV directly (without the matrix).
  • Try using GL_R8 (internal format) and GL_RED (external format) rather than GL_LUMINANCE. GL_LUMINANCE isn’t supported in the core profile; I don’t know whether that applies to core-profile shaders used with a compatibility-profile context.