I keep having a random error trying to print some image with OpengGL via ImGui library (GLFW as back-end).
Here is what gdb give me so far :
#0 0x00000000400b0ef1 in ?? ()
#1 0x00007ffec1b80fb0 in ?? ()
#2 0x00007ffeda7f5780 in ?? ()
#3 0x00007fffffffdca0 in ?? ()
#4 0x0000000000000735 in ?? ()
#5 0x00007ffff4e52a8d in ?? () from /lib/x86_64-linux-gnu/libnvidia-glcore.so.510.60.02
#6 0x00007ffff4e5caa9 in ?? () from /lib/x86_64-linux-gnu/libnvidia-glcore.so.510.60.02
#7 0x00007ffff4f71830 in ?? () from /lib/x86_64-linux-gnu/libnvidia-glcore.so.510.60.02
#8 0x00007ffff4f7cd9d in ?? () from /lib/x86_64-linux-gnu/libnvidia-glcore.so.510.60.02
#9 0x00007ffff4f7e334 in ?? () from /lib/x86_64-linux-gnu/libnvidia-glcore.so.510.60.02
#10 0x00007ffff4f7e6c1 in ?? () from /lib/x86_64-linux-gnu/libnvidia-glcore.so.510.60.02
#11 0x00005555556552ec in Texture::sendToGPU (this=0x5555565c00f8) at /media/romain/Donnees/Programmation/C++/frameworks/opengl/Texture.cpp:136
#12 0x00005555555f8e57 in exImage::<lambda()>::<lambda()>::operator()(void) const (__closure=0x7fffffffe2e8)
at /media/romain/Donnees/Programmation/C++/cmake/fxplorer/src/ui/exImage.cpp:14
What's weird, it this only appen when I load the images data in multithreaded mode. (each image is loaded on a separate thread at the same time)
When I transform my code as singlethreaded, there is no crash.
BUT, the GPU code (the sendToGPU method here : )
void Texture::glInit()
{
gl_call(glGenTextures(1, &glId));
lg2("GLid", glId);
this->bind();
gl_call(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
gl_call(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
gl_call(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
gl_call(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
this->unbind();
}
void Texture::load(unsigned char* data, const unsigned int &w, const unsigned int &h, const unsigned int &bpp)
{
this->loadCPU(data, w, h, bpp);
// this part NEED to be executed on the MAIN THREAD ! :/
this->sendToGPU();
}
// could be excecuted on a thread!
// the data is being held by the Texture, you can't deleted after calling this method. It will be deleted when you call the method unload or when you destry the Texture
void Texture::loadCPU(unsigned char* data, const unsigned int &w, const unsigned int &h, const unsigned int &bpp, bool* doned)
{
std::lock_guard<std::mutex> l(_mtx);
if (doned)
*doned = false;
_cpuLoaded = false;
_width = w;
_height = h;
_bpp = bpp;
_bpc = img::bpcFromBpp(_bpp);
_channels = img::nbOfChannelFromBpp(_bpp);
int length = w*h*_channels*(_bpc/8);
_data = data;
if (!_data)
return;
if (doned)
*doned = true;
_cpuLoaded = true;
}
void Texture::loadCPU(const char* filepath, bool* doned)
{
std::lock_guard<std::mutex> l(_mtx);
if (!filepath)
{
lg("filepath does not exists !");
return;
}
if (doned)
*doned = false;
_cpuLoaded = false;
_data = img::openGLFormatted(filepath, &_width, &_height, &_bpp);
if (!_data)
return;
_bpc = img::bpcFromBpp(_bpp);
_channels = img::nbOfChannelFromBpp(_bpp);
if (doned)
*doned = true;
_cpuLoaded = true;
}
void Texture::unload(const bool &cpu, const bool &gpu)
{
std::lock_guard<std::mutex> l(_mtx);
if (cpu && _data)
{
delete[] _data;
}
if (gpu)
{
gl_call(glDeleteTextures(1, &glId));
}
}
void Texture::bind(unsigned int slot )
{
//gl_call(glActiveTexture(GL_TEXTURE0 + slot)); // not sure what it does... for now it make the profgram segfault
gl_call(glBindTexture(GL_TEXTURE_2D, glId));
}
void Texture::unbind()
{
gl_call(glBindTexture(GL_TEXTURE_2D, 0));
}
void Texture::sendToGPU()
{
_mtx.lock();
this->glInit();
this->bind();
lg(_width << " x " << _height << " - " << _bpp <<" bits/pxl");
if (_bpp == 24)
{
gl_call(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, _width, _height, 0, GL_RGB, GL_UNSIGNED_BYTE, _data));
}
else if (_bpp == 32)
{
gl_call(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, _width, _height, 0, GL_RGBA, GL_UNSIGNED_BYTE, _data));
}
else if (_bpp == 48)
{
gl_call(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB16, _width, _height, 0, GL_RGB, GL_UNSIGNED_SHORT, _data));
}
else if (_bpp == 64)
{
gl_call(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16, _width, _height, 0, GL_RGBA, GL_UNSIGNED_SHORT, _data));
}
else if (_bpp == 96)
{
gl_call(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB32F, _width, _height, 0, GL_RGB, GL_FLOAT, _data));
}
else if (_bpp == 128)
{
gl_call(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, _width, _height, 0, GL_RGBA, GL_FLOAT, _data));
}
//gl_call(glGenerateMipmap(GL_TEXTURE_2D)); // not sure whaat is it - make the program crash for now.
this->unbind();
//
_gpuLoaded = true;
_mtx.unlock();
}
Is always executed on the mainthread (the same as GLFW context - I checked it a million time). So I've been thinking there is a data race condition somewhere. But impossible to find it so far. (the _data attribute is locked between mutex AND is not used anywhere else in my code)
It seams to crash at the line :
gl_call(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, _width, _height, 0, GL_RGB, GL_UNSIGNED_BYTE, _data));
Are you aware of what can make this line crash ? I've been thinking of a bad formatted _data but like it works on singlethreaded mode, there is no reason this is it.
The crashes are totally random and seam to be present when the images are pretty large (like 2k of 4k) but it's not always the case.
I'm a beginner in the OpenGL world and I think there are some concepts I don't fully understand... So if you think I'm not making any sense with my explanations, feel free to correct me ! :)
If you have any idea why this is happening, don't hesitate to share !
When a RGB image with 3 color channels is loaded to a texture object and 3*width is not divisible by 4, GL_UNPACK_ALIGNMENT
has to be set to 1, before specifying the texture image with glTexImage2D
:
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, _width, _height, 0, GL_RGB, GL_UNSIGNED_BYTE, _data);
By default OpenGL GL_UNPACK_ALIGNMENT
is 4 bytes. Since the lines of your image are not aligned to 4 bytes, glTexImage2D
accesses unallocated memory, which leads to your problems.