0

I have this bit of OpenGL/Python code:

import sys

from OpenGL.GL import *
from OpenGL.GL import shaders
from OpenGL.GLU import *
from OpenGL.GLUT import *

glutInit(sys.argv)
glutInitDisplayMode(GLUT_RGBA)
glutInitWindowSize(640, 480)
window = glutCreateWindow("Test")

print glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS)
print glGetIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS)
print glGetIntegerv(0x8872)
print glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS)

fs = (
"""
#version 130

uniform sampler2D foo;
uniform samplerCube bar;

void main()
{
    vec4 c1 = texture2D(foo, vec2(0, 0));
    vec4 c2 = textureCube(bar, vec3(0, 0, 0));
    gl_FragColor = c1 + c2;
}
"""
)

shader = shaders.compileShader(fs, GL_FRAGMENT_SHADER)
program = shaders.compileProgram(shader)
print program

When I run it, the fragment shader fails to compile:

$ python tex.py 
16
16
16
48
Traceback (most recent call last):
  File "tex.py", line 35, in <module>
    program = shaders.compileProgram(shader)
  File "/usr/local/lib/python2.7/dist-packages/OpenGL/GL/shaders.py", line 196, in compileProgram
    program.check_validate()
  File "/usr/local/lib/python2.7/dist-packages/OpenGL/GL/shaders.py", line 108, in check_validate
    glGetProgramInfoLog( self ),
RuntimeError: Validation failure (0): Texture unit 0 is accessed both as sampler2D and samplerCube

I don't see why the two sampler objects would bind to the same texture units? Using GLSL 1.30, I don't even see how I can specify texture units before compiling the program. And it should be possible to use multiple samplers and texture units.

What am I doing wrong?

Vegard
  • 2,081
  • 1
  • 17
  • 26

2 Answers2

3

You probably either left the sampler uniform values at default or set 0 for either one. Which is obviously wrong.

Your drawing texture binding code should look like this:

glActiveTexture(GL_TEXTURE0 + x)
glBindTexture(GL_TEXTURE_2D, …)
glUniform1i(uniform_location_of_foo, x)


glActiveTexture(GL_TEXTURE0 + y)
glBindTexture(GL_TEXTURE_CUBE_MAP, …)
glUniform1i(uniform_location_of_bar, y)

I.e. the sampler uniform integer values must correspond to the texture unit to which a matching texture target has been bound.

datenwolf
  • 159,371
  • 13
  • 185
  • 298
  • Note that this happens before the shader has even been compiled. So neither the program nor the uniform (location) even exist yet AFAIU... – Vegard Aug 26 '15 at 22:15
  • 2
    I have a feeling it's PyOpenGL's fault for calling `glValidateProgram()` which depends on the OpenGL state. I'll try skipping that step and see if it validates correctly *after* binding the textures. Thanks! – Vegard Aug 26 '15 at 22:24
  • 2
    @Vegard: That is poor design on PyOpenGL's part then. I would hope that this behavior is defeatable because programs don't necessarily need to be in a valid working state immediately. It's a common scenario to call `glUseProgram (...)` and later setup texture image units and other supporting state. The best time to validate program state would be immediately prior to a `glDraw* (...)` call - doing it at any other point is premature for the reasons outlined above. – Andon M. Coleman Aug 28 '15 at 19:39
0

I have just recently started learning OpenGL myself, so I'm not familiar with all the ins and outs of it. However, I had the same problem and it was because I was attempting to validate the shaders before I had assigned the uniforms to their respective units. The problem was fixed after I did everything in the following order:

        glLinkProgram(m_Program);

        m_Uniforms[DIFFUSE_U]   = glGetUniformLocation(m_Program, "diffuse");
        m_Uniforms[NORMALMAP_U] = glGetUniformLocation(m_Program, "normalMap");
        m_Uniforms[SHADOWMAP_U] = glGetUniformLocation(m_Program, "shadowMap");

        glUseProgram(m_Program);

        glUniform1i(m_Uniforms[DIFFUSE_U], 0);//sets the diffuse sampler to the texture bound as unit 0
        glUniform1i(m_Uniforms[NORMALMAP_U], 1);
        glUniform1i(m_Uniforms[SHADOWMAP_U], 2);

        glValidateProgram(m_Program);
Sina
  • 21
  • 2
  • You need a `glUseProgram()` call between `glLinkProgram()` and the `glUniform1i()` calls. `glUniform1i()` applies to the current program. – Reto Koradi Jan 14 '16 at 03:51
  • Thanks, I edited the code to show where glUseProgram() would go. – Sina Jan 14 '16 at 04:53