Debugging OpenGL纹理加载问题

Debugging OpenGL纹理加载问题,debugging,opengl,3d,texturing,Debugging,Opengl,3d,Texturing,这是一个非常模糊的问题,所以请随时澄清任何关于这个项目 我正在开发一个非常大的应用程序,最近出现了一个关于纹理的非常复杂的错误。我们正在加载的一些纹理正在加载中-我已经详细介绍了代码,它正在运行-但是所有这些纹理的OpenGL渲染都是奇怪的粉色/白色条纹纹理 您建议如何开始调试这种情况 该项目是多线程的,但互斥锁确保所有OpenGL调用不会被其他任何东西中断。 有些纹理正在加载,有些没有加载。它们都是以完全相同的方式装载的。 我已确保所有纹理都存在 粉色/白色纹理肯定会加载到内存中-在我将任何其

这是一个非常模糊的问题,所以请随时澄清任何关于这个项目

我正在开发一个非常大的应用程序,最近出现了一个关于纹理的非常复杂的错误。我们正在加载的一些纹理正在加载中-我已经详细介绍了代码,它正在运行-但是所有这些纹理的OpenGL渲染都是奇怪的粉色/白色条纹纹理

您建议如何开始调试这种情况

该项目是多线程的,但互斥锁确保所有OpenGL调用不会被其他任何东西中断。 有些纹理正在加载,有些没有加载。它们都是以完全相同的方式装载的。 我已确保所有纹理都存在 粉色/白色纹理肯定会加载到内存中-在我将任何其他纹理加载到OpenGL后不久,它们就会可见。 我很困惑,不知道还有什么不对劲。是否有一个OpenGL命令可以在glTexImage之后调用,从而强制纹理变得可用

编辑: 这与命令失败无关,主要是时间问题。粉色/白色纹理会显示一段时间,直到加载更多纹理。这几乎就像纹理在排队,而队列只是在某个时间暂停

下一次编辑:我让glIntercept日志正常工作,这是它在整个程序崩溃之前输出的结果


下一步编辑:我知道纹理加载到OpenGL内存中,但由于某些原因,它们本身并没有在程序中渲染

检查用作纹理的图像的大小和压缩。我认为opengl纹理大小必须是2的幂…

检查用作纹理的图像的大小和压缩。我认为opengl纹理大小必须是2的幂…

如果你的纹理颜色不正确,很可能你加载了错误的RGB顺序。确保在glTexImage2D中为图像格式使用了正确的枚举。确保组件的数量正确,并且格式参数中的RGB像素顺序正确

尽管可能与错误显示的纹理无关,但OpenGL不支持多线程绘制,因此请确保您没有在与拥有上下文的线程不同的线程上进行任何绘制工作


编辑:您是否有一个参考渲染器,以便验证图像像素是否按预期加载?我强烈建议编写一个小例程来加载,然后立即将像素保存到文件中,这样您就可以确保获得正确的纹理结果。

如果您的纹理颜色不正确,则很可能是加载了错误的RGB顺序。确保在glTexImage2D中为图像格式使用了正确的枚举。确保组件的数量正确,并且格式参数中的RGB像素顺序正确

尽管可能与错误显示的纹理无关,但OpenGL不支持多线程绘制,因此请确保您没有在与拥有上下文的线程不同的线程上进行任何绘制工作

编辑:您是否有一个参考渲染器,以便验证图像像素是否按预期加载?我强烈建议编写一个小例程来加载,然后立即将像素保存到文件中,这样您就可以确保获得正确的纹理结果。

当您说:

该项目是多线程的,但互斥锁确保所有OpenGL调用不会被其他任何东西中断

对我来说,这听起来不够强大:记住OpenGL是一个具有大量内部状态的状态机。您需要确保OpenGL状态是您在进行调用时所期望的状态,并且某些调用序列不会被其他线程的调用中断

我不是OpenGL线程安全方面的专家,但在我看来,这可能是您的问题所在。

当您说:

该项目是多线程的,但互斥锁确保所有OpenGL调用不会被其他任何东西中断

对我来说,这听起来不够强大:记住OpenGL是一个具有大量内部状态的状态机。您需要确保OpenGL状态是您在进行调用时所期望的状态,并且某些调用序列不会被其他线程的调用中断


我不是OpenGL线程安全方面的专家,但在我看来,这可能是您的问题所在。

检查您的纹理坐标。如果设置错误,则只能看到映射到整个基本体的一个或两个texel。记住,OpenGL是一个状态机。检查是否在错误的时间更改纹理坐标状态。您可能会在代码中的稍后点设置纹理坐标,然后当您重新绘制这些元素时,可以接受将纹理映射到代码的状态


如果只是时间问题,纹理加载OpenGL调用没有及时执行,并且线程代码正确,请尝试在加载纹理后添加对glFlush的调用。glFlush导致执行所有挂起的OpenGL命令

检查纹理坐标。如果设置错误,则只能看到映射到整个基本体的一个或两个texel。记住,OpenGL是一个状态机。检查是否在错误的时间更改纹理坐标状态。您可能会在代码中的稍后点设置纹理坐标,然后当您重新绘制这些元素时,可以接受将纹理映射到代码的状态


如果只是时间问题,纹理加载OpenGL调用没有及时执行,并且线程代码正确,请尝试在加载纹理后添加对glFlush的调用。glFlush导致执行所有挂起的OpenGL命令

您不能在线程中加载纹理并在其他不同的线程中使用,因为您将看到美丽的白色纹理。要做到这一点,您必须在使用任何OpenGL函数之前在不同线程之间加载OpenGL上下文。

您不能在线程中加载纹理并在其他不同线程中使用,因为您将看到美丽的白色纹理。要做到这一点,在使用任何OpenGL函数之前,必须在不同线程之间加载OpenGL上下文。

如果使用GLIntercept检查代码,请确保启用: 线程检查=真; 在gliConfig.ini文件中


查看日志时,似乎有相当多的OpenGL调用是主上下文之外的主调用。

如果使用GLIntercept检查代码,请确保启用: 线程检查=真; 在gliConfig.ini文件中


查看日志时,似乎有相当多的OpenGL调用是主上下文之外的主调用。

可以在另一个线程中加载纹理,而不获得白色纹理。问题是,一旦初始化了OpenGL窗口,OpenGL上下文就绑定到此线程。加载纹理时,必须停用主线程中的上下文,在开始加载纹理之前,必须激活此线程中的上下文

您可以使用该类:

背景.h:

#ifndef CONTEXT_H
#define CONTEXT_H

#include <GL/glut.h>

class Context
{
public:
    static Context* getInstance();

    void bind();
    void unbind();
private:
    Context();
    Context(const Context&);
    ~Context();

    static Context *instance;

    HGLRC hglrc;
    HDC hdc;

    class Guard
    {
    public:
        ~Guard()
        {
            if (Context::instance != 0) {
                delete Context::instance;
            }
        }
    };
    friend class Guard;
};

#endif
这就是你必须要做的:

int state = 0;

void main()
{
    // Create the window.
    glutCreateWindow(TITLE);

    // Set your loop function.
    glutDisplayFunc(&loop);

    // Initialize the singleton for the 1st time.
    Context::getInstance()->bind();

    glutMainLoop();
}

void loop()
{
    if (state == 0) {
        Context::getInstance()->unbind();
        startThread(&run);
    } else if (state == 1) {
        // Rebind the context to the main thread (just once).
        Context::getInstance()->bind();
        state = 2;
    } else if (state == 2) {
        // Draw your textures, lines, etc.
    } else {
        // Draw something (but no textures).
    }
}

void run()
{
    Context::getInstance()->bind();

    // Load textures...

    Context::getInstance()->unbind();
    state = 1;
}

可以在另一个线程中加载纹理而不获得白色纹理。问题是,一旦初始化了OpenGL窗口,OpenGL上下文就绑定到此线程。加载纹理时,必须停用主线程中的上下文,在开始加载纹理之前,必须激活此线程中的上下文

您可以使用该类:

背景.h:

#ifndef CONTEXT_H
#define CONTEXT_H

#include <GL/glut.h>

class Context
{
public:
    static Context* getInstance();

    void bind();
    void unbind();
private:
    Context();
    Context(const Context&);
    ~Context();

    static Context *instance;

    HGLRC hglrc;
    HDC hdc;

    class Guard
    {
    public:
        ~Guard()
        {
            if (Context::instance != 0) {
                delete Context::instance;
            }
        }
    };
    friend class Guard;
};

#endif
这就是你必须要做的:

int state = 0;

void main()
{
    // Create the window.
    glutCreateWindow(TITLE);

    // Set your loop function.
    glutDisplayFunc(&loop);

    // Initialize the singleton for the 1st time.
    Context::getInstance()->bind();

    glutMainLoop();
}

void loop()
{
    if (state == 0) {
        Context::getInstance()->unbind();
        startThread(&run);
    } else if (state == 1) {
        // Rebind the context to the main thread (just once).
        Context::getInstance()->bind();
        state = 2;
    } else if (state == 2) {
        // Draw your textures, lines, etc.
    } else {
        // Draw something (but no textures).
    }
}

void run()
{
    Context::getInstance()->bind();

    // Load textures...

    Context::getInstance()->unbind();
    state = 1;
}

OpenGL支持NPOT纹理(假设图形卡支持)。过去6-7年左右制作的大多数视频卡都支持NPOT纹理。它们不一定要支持NPOT纹理,这是对大多数旧视频卡的建议。也就是说,在我的例子中,这是一个时间问题,因为纹理最终会正确加载。如果您有ARB_texture_non_power_of_two扩展,则不会。现在这非常常见。OpenGL支持NPOT纹理,假设您的图形卡支持。过去6-7年左右制作的大多数视频卡都支持NPOT纹理。它们不一定要支持NPOT纹理,这是对大多数旧视频卡的建议。也就是说,在我的例子中,这是一个时间问题,因为纹理最终会正确加载。如果你有ARB_texture_non_power_of_two扩展,这就不是问题了,而且现在非常普遍。像素正在加载,但在存在多个请求该图片的绘图之前不会更新到OpenGL中。我知道这一点的原因是,粉红色/白色纹理将被请求的实际纹理替换,但仅在加载更多纹理之后。我知道这不是加载的原因是因为相同的粉色/白色纹理是一致的-无论出于何种原因,它在所有未正确加载的纹理中以相同的方式显示。您的线程设置是什么?您没有在线程外调用任何gl***函数,对吗?请尝试一下glIntercept,它会将您的opengl32.dll替换为将调用历史记录记录到文件中的opengl32.dll。确保你的调用按正确的顺序进行。另外,当你在代码中创建一个纹理时会发生什么?只需制作一个全红色/绿色的图像并加载它,它是否还会在一段时间内显示为粉色/白色?我认为在加载操作实际发生之前,粉红色/白色纹理就是该位置内存中的内容。glIntercept会导致程序崩溃,而不会显示任何内容…像素正在加载,但在存在多个请求该图片的绘图之前,不会更新到OpenGL中。我知道这一点的原因是,粉红色/白色纹理将被请求的实际纹理替换,但仅在加载更多纹理之后。我知道这不是加载的原因是因为相同的粉色/白色纹理是一致的-它在所有没有正确加载的纹理中以相同的方式显示,例如w

没有理由。你的线程设置是什么?您没有在线程外调用任何gl***函数,对吗?请尝试一下glIntercept,它会将您的opengl32.dll替换为将调用历史记录记录到文件中的opengl32.dll。确保你的调用按正确的顺序进行。另外,当你在代码中创建一个纹理时会发生什么?只需制作一个全红色/绿色的图像并加载它,它是否还会在一段时间内显示为粉色/白色?我认为在加载操作实际发生之前,粉红色/白色纹理就是那个位置的内存。glIntercept导致我们的程序崩溃,而没有显示任何东西…说得好-我尝试解决它的方向是让它与GLTrace一起工作,看看它是否能提供更多信息。哪些状态变量会影响纹理何时可用?很好地说明-我尝试解决它的方向是让它与GLTrace一起工作,看看它是否会提供更多信息。哪些状态变量会影响纹理何时可用?第一部分肯定不是问题所在,因为纹理坐标在它们之间实际上从未改变过,也没有改变。在渲染循环中间有没有调用GLFHUP的副作用?我不知道为什么添加GLFHUP是有效的,但是它确实做到了,所以你得到了认可!不过,我很想知道为什么。它还使程序加速了五倍。几乎可以肯定的是,您看到的是glTexImage2D的缓冲延迟,它读取的内存由于draw调用的设置方式而在几帧内没有初始化。如果您使用的是显示列表,这通常是一个大问题,因为它们是经过编译的,并且可能以您意想不到的方式执行操作。我不知道glTexImage2D上有任何延迟-它似乎在其所有行为中都是一个阻塞函数。请阅读关于glFlush的文档,即使glFlush调用本身也可能不会在整个过程中阻塞处理!第一部分绝对不是问题所在,因为纹理坐标在它们之间从未实际更改过,也不会发生变化。在渲染循环中间有没有调用GLFHUP的副作用?我不知道为什么添加GLFHUP是有效的,但是它确实做到了,所以你得到了认可!不过,我很想知道为什么。它还使程序加速了五倍。几乎可以肯定的是,您看到的是glTexImage2D的缓冲延迟,它读取的内存由于draw调用的设置方式而在几帧内没有初始化。如果您使用的是显示列表,这通常是一个大问题,因为它们是经过编译的,并且可能以您意想不到的方式执行操作。我不知道glTexImage2D上有任何延迟-它似乎在其所有行为中都是一个阻塞函数。请阅读关于glFlush的文档,即使glFlush调用本身也可能不会在整个过程中阻塞处理!还有另一种方法:像素缓冲区对象扩展允许异步纹理加载。。。但这个扩展不适用于旧的图形卡或旧的驱动程序。还有另一种方法:像素缓冲区对象扩展允许异步纹理加载。。。但是这个扩展不适用于旧的图形卡或旧的驱动程序。