使用glTexImage2D和NVIDIA时出现OpenGL错误

pgvzfuti  于 2022-09-26  发布在  其他
关注(0)|答案(1)|浏览(265)

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

以下是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));

你知道是什么原因会导致这条线路相撞吗?我一直在想一个不好的Formted_Data,但就像它在单线程模式下工作一样,没有理由就是这样。

崩溃完全是随机的,当图像很大时(比如2k或4k),就会出现Seam,但情况并不总是这样。

我是OpenGL世界的初学者,我认为有些概念我不完全理解……因此,如果您认为我的解释没有任何意义,请随时纠正我!:)

如果你知道为什么会发生这种情况,请毫不犹豫地与我们分享!

olqngx59

olqngx591#

如果将具有3个颜色通道的RGB图像加载到纹理对象,并且3*宽度不能被4整除,则在使用glTexImage2D指定纹理图像之前,必须将GL_UNPACK_ALIGNMENT设置为1:

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访问未分配的内存,这会导致您的问题。

相关问题