High severity error: Special case for sampler type should be handled differently in the AbstractUniform
Currently getting a high severity error reported while setting a uniform value for a sampler, I found this documentation on Khronos website:
Notes
glProgramUniform1i and glProgramUniform1iv are the only two functions that may be used to load uniform variables defined as sampler types. Loading samplers with any other function will result in a GL_INVALID_OPERATION error.
I'm getting this message from NVidia's driver:
error: 0x502, high severity (API) GL_INVALID_OPERATION error generated. <apiElementType> value is invalid; expected GL_INT or GL_UNSIGNED_INT64_NV.
while calling this code:
program->use();
The call stack is:
#2 0x00000000006eb9f9 in globjects::DebugImplementation_DebugKHR::debugMessageCallback(gl::GLenum, gl::GLenum, unsigned int, gl::GLenum, int, char const*, void const*) ()
#3 0x00007ffff130eb18 in ?? () from /lib64/libnvidia-glcore.so.367.57
#4 0x00007ffff130ec60 in ?? () from /lib64/libnvidia-glcore.so.367.57
#5 0x00007ffff130ef22 in ?? () from /lib64/libnvidia-glcore.so.367.57
#6 0x00007ffff14a78ac in ?? () from /lib64/libnvidia-glcore.so.367.57
#7 0x00007ffff14b1075 in ?? () from /lib64/libnvidia-glcore.so.367.57
#8 0x00007ffff14c720c in ?? () from /lib64/libnvidia-glcore.so.367.57
#9 0x000000000080c229 in glbinding::Function<void, unsigned int, int, unsigned int>::call(unsigned int&, int&, unsigned int&) const ()
#10 0x00000000007ff52b in gl::glProgramUniform1ui(unsigned int, int, unsigned int) ()
#11 0x000000000064d5ab in globjects::Uniform<unsigned int>::updateAt (this=0x13594c0, program=0x1309f90, location=8) at /usr/local/include/globjects/Uniform.inl:54
#12 0x00000000006e57e5 in globjects::AbstractUniform::update(globjects::Program const*, bool) const ()
#13 0x00000000006ecd50 in globjects::Program::updateUniforms() const ()
#14 0x00000000006ee084 in globjects::Program::link() const ()
#15 0x00000000006ee0f5 in globjects::Program::use() const ()
For this location, I suspect that setting the texture's sampler index (used 0) is being recorded as Uniform<unsigned int> and calls glProgramUniform1ui while the standard clearly say we should call glProgramUniform1i (see first note on this issue).
This is a hard problem to solve, since globject deducts the type of the uniform from its type, so the deduction of Uniform<unsigned int> is correct when passed 0.
I don't know how to solve it logically. I can force the type to int and it'll work, but I guess that force all client code to write a specific case when setting sampler types. I wonder if a specific Program::setSamplerUniform would not be more explicit ?
In that case, the code for such method would be straightforward:
inline void setSamplerUniform(const std::string & name, const int value) { setUniform(name, value); }
inline void setSamplerUniform(gl::GLint location, const int value) { setUniform(location, value); }
What do you think ?
To bind a location to a sampler, the OpenGL specification expects a signed integer (or a 64-bit unsigned integer for bindless textures).
Using globjects, uniforms can be added to a program by calling templates member functions. (e.g., program->addUniform<int>("mySampler", 0);
I use the explicit template parameter type to bypass any template parameter deduction that may lead to wrong/unexpected types.
This may help in your case.
More generally, we could introduce a user-defined type (e.g., a struct or enum) that encapsulates sampler locations and provide member function overrides on Uniform that calls the integer variant internally.