繁体   English   中英

OpenGL glTexImage2D 和 NVIDIA 错误

[英]OpenGL Error with glTexImage2D and NVIDIA

我一直在尝试通过 ImGui 库(GLFW 作为后端)使用 OpenGL 打印一些图像时出现随机错误。

这是 gdb 到目前为止给我的:

#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

奇怪的是,这只发生在我以多线程模式加载图像数据时。 (每个图像同时加载到单独的线程上)

当我将我的代码转换为单线程时,没有崩溃。

但是,GPU 代码(此处的 sendToGPU 方法:)

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();
}

始终在主线程上执行(与 GLFW 上下文相同 - 我检查了一百万次)。 所以我一直认为某处存在数据竞争情况。 但目前不可能找到它。 (_data 属性在互斥锁之间被锁定,并且在我的代码中的其他任何地方都没有使用)

它似乎在这条线上崩溃:

gl_call(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, _width, _height, 0, GL_RGB, GL_UNSIGNED_BYTE, _data));

你知道什么会导致这条线崩溃吗? 我一直在考虑格式错误的 _data 但就像它在单线程模式下工作一样,没有理由就是这样。

当图像非常大(如 2k 或 4k)时,崩溃是完全随机的,并且会出现接缝,但情况并非总是如此。

我是 OpenGL 世界的初学者,我认为有些概念我并不完全理解......所以如果你认为我的解释没有任何意义,请随时纠正我::)

如果您知道为什么会发生这种情况,请随时分享!

当具有 3 个颜色通道的 RGB 图像加载到纹理 object 并且 3*width 不能被 4 整除时,必须将GL_UNPACK_ALIGNMENT设置为 1,然后再使用glTexImage2D指定纹理图像:

glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, _width, _height, 0, GL_RGB, GL_UNSIGNED_BYTE, _data);

默认情况下 OpenGL GL_UNPACK_ALIGNMENT为 4 个字节。 由于您的图像行未对齐到 4 个字节, glTexImage2D访问未分配的 memory,这会导致您的问题。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM