cginternals / globjects

C++ library strictly wrapping OpenGL objects.
https://globjects.org
MIT License
539 stars 59 forks source link

High severity error: Special case for sampler type should be handled differently in the AbstractUniform #334

Open X-Ryl669 opened 7 years ago

X-Ryl669 commented 7 years ago

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. 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 ?

scheibel commented 7 years ago

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.