You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

销毁QOffscreenSurface子类时程序崩溃的原因排查

问题:Qt离屏渲染析构时删除QOpenGLContext触发断言错误

我使用QOffscreenSurface和QOpenGLContext实现纹理离屏渲染,调用OffscreenRender::paint()后可以在纹理tbo中心渲染矩形,但在析构函数中调用delete openGLContext;时,Qt会触发断言错误:ASSERT: "d_1_0_Core->refs.load()" in file opengl\qopenglfunctions_4_3_core.cpp, line 93。移除该delete语句后程序运行正常,求原因。


相关代码

OffscreenRender.h

class OffscreenRender:public QOffscreenSurface,protected QOpenGLFunctions_4_3_Core
{
    Q_OBJECT
public:
    explicit OffscreenRender(QObject *parent = 0);
    virtual ~OffscreenRender();
    void paint();
    GLuint* getTBO();
    QOpenGLContext *getCurrentContext(){return openGLContext;}
private:
    void initialGL();
private:
    bool glInitialized = false;
    QOpenGLContext *openGLContext = nullptr;
    GLuint proGen = 0,
    vaoGen = 0,
    vboGen = 0,
    tbo = 0,
    fbo = 0;
};

OffscreenRender.cpp

OffscreenRender::OffscreenRender(QObject *parent)
{
    setParent(parent);
    QSurfaceFormat surfaceFormat;
    surfaceFormat.setMajorVersion(4);
    surfaceFormat.setMinorVersion(3);
    surfaceFormat.setProfile(QSurfaceFormat::CoreProfile);

    openGLContext = new QOpenGLContext();
    openGLContext->setFormat(surfaceFormat);
    QOpenGLContext *share = QOpenGLContext::globalShareContext();
    openGLContext->setShareContext(share);

    if(openGLContext->create()){
        setFormat(surfaceFormat);
        create();
        if(!isValid())
            qDebug("Unable to create the Offscreen surface");
            initialGL();
    }
    else{
        qDebug("Unable to create the context");
    }
}

OffscreenRender::~OffscreenRender(){
    openGLContext->makeCurrent(this);
    if(glIsProgram(proGen)){
        glDeleteProgram(proGen);
    }
    if(glIsVertexArray(vaoGen)){
        glDeleteVertexArrays(1,&vaoGen);
    }
    if(glIsBuffer(vboGen)){
        glDeleteBuffers(1,&vboGen);
    }
    if(glIsTexture(tbo)){
        glDeleteTextures(1,&tbo);
    }
    if(glIsFramebuffer(fbo)){
        glDeleteFramebuffers(1,&fbo);
    }
    openGLContext->doneCurrent();
    if(openGLContext){
        delete openGLContext;
    }
}

void OffscreenRender::paint(){
    if(glInitialized){
        openGLContext->makeCurrent(this);
        glViewport(0, 0, 100, 100);
        glClearColor(1,0,1,1);
        glUseProgram(proGen);
        glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
        glDrawBuffer(GL_COLOR_ATTACHMENT0);
        glClear(GL_COLOR_BUFFER_BIT);
        glBindVertexArray(vaoGen);
        glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
        openGLContext->doneCurrent();
    }
}

GLuint *OffscreenRender::getTBO(){return &tbo;}

void OffscreenRender::initialGL(){
    openGLContext->makeCurrent(this);
    if(!initializeOpenGLFunctions()){
        qDebug("Unable to initialize the functions");
        return;
    }
    proGen = loadShaders();

    glGenVertexArrays(1, &vaoGen);
    glBindVertexArray(vaoGen);

    glGenBuffers(1, &vboGen);
    glBindBuffer(GL_ARRAY_BUFFER,vboGen);
    int nBytes = sizeof(float) * 16;
    glBufferData(GL_ARRAY_BUFFER,nBytes,vertexCord,GL_STATIC_DRAW);
    glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 4, NULL);
    glEnableVertexAttribArray(0);

    glActiveTexture(GL_TEXTURE0);
    glGenTextures(1, &tbo);
    glBindTexture(GL_TEXTURE_2D, tbo);
    glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA32F, 100, 100);

    glGenFramebuffers(1, &fbo);
    glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
    glFramebufferTexture(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tbo, 0);
    openGLContext->doneCurrent();
    glInitialized = true;
}

原因分析与解决方法

核心原因

你的OffscreenRender类直接继承了QOpenGLFunctions_4_3_Core,这个类的内部实现会与当前绑定的QOpenGLContext建立关联并维护引用计数。当你在析构函数中先调用openGLContext->doneCurrent()再删除上下文时,QOpenGLFunctions_4_3_Core的实例(即你的OffscreenRender对象)还未销毁,其内部资源仍持有对已销毁上下文的引用,导致引用计数不匹配,触发断言。

解决方法

最稳妥的方式是用组合替代继承,避免QOpenGLFunctions_4_3_Core的生命周期与类本身强绑定,手动控制其销毁顺序:

  1. 修改头文件,将继承改为组合:
class OffscreenRender:public QOffscreenSurface
{
    Q_OBJECT
public:
    explicit OffscreenRender(QObject *parent = 0);
    virtual ~OffscreenRender();
    void paint();
    GLuint* getTBO();
    QOpenGLContext *getCurrentContext(){return openGLContext;}
private:
    void initialGL();
private:
    bool glInitialized = false;
    QOpenGLContext *openGLContext = nullptr;
    QOpenGLFunctions_4_3_Core *glFuncs = nullptr; // 改为组合方式
    GLuint proGen = 0,
    vaoGen = 0,
    vboGen = 0,
    tbo = 0,
    fbo = 0;
};
  1. 初始化GL函数对象,所有GL调用改为通过该对象调用:
void OffscreenRender::initialGL(){
    openGLContext->makeCurrent(this);
    glFuncs = new QOpenGLFunctions_4_3_Core();
    if(!glFuncs->initializeOpenGLFunctions()){
        qDebug("Unable to initialize the functions");
        delete glFuncs;
        glFuncs = nullptr;
        return;
    }
    proGen = loadShaders();

    glFuncs->glGenVertexArrays(1, &vaoGen);
    glFuncs->glBindVertexArray(vaoGen);

    glFuncs->glGenBuffers(1, &vboGen);
    glFuncs->glBindBuffer(GL_ARRAY_BUFFER,vboGen);
    int nBytes = sizeof(float) * 16;
    glFuncs->glBufferData(GL_ARRAY_BUFFER,nBytes,vertexCord,GL_STATIC_DRAW);
    glFuncs->glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 4, NULL);
    glFuncs->glEnableVertexAttribArray(0);

    glFuncs->glActiveTexture(GL_TEXTURE0);
    glFuncs->glGenTextures(1, &tbo);
    glFuncs->glBindTexture(GL_TEXTURE_2D, tbo);
    glFuncs->glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA32F, 100, 100);

    glFuncs->glGenFramebuffers(1, &fbo);
    glFuncs->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
    glFuncs->glFramebufferTexture(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tbo, 0);
    openGLContext->doneCurrent();
    glInitialized = true;
}
  1. 调整析构函数顺序,先销毁GL函数对象,再删除上下文:
OffscreenRender::~OffscreenRender(){
    if(glFuncs){
        openGLContext->makeCurrent(this);
        if(glFuncs->glIsProgram(proGen)){
            glFuncs->glDeleteProgram(proGen);
        }
        if(glFuncs->glIsVertexArray(vaoGen)){
            glFuncs->glDeleteVertexArrays(1,&vaoGen);
        }
        if(glFuncs->glIsBuffer(vboGen)){
            glFuncs->glDeleteBuffers(1,&vboGen);
        }
        if(glFuncs->glIsTexture(tbo)){
            glFuncs->glDeleteTextures(1,&tbo);
        }
        if(glFuncs->glIsFramebuffer(fbo)){
            glFuncs->glDeleteFramebuffers(1,&fbo);
        }
        delete glFuncs;
        glFuncs = nullptr;
    }
    if(openGLContext){
        openGLContext->doneCurrent();
        delete openGLContext;
        openGLContext = nullptr;
    }
}

这样修改后,GL函数对象会先于上下文销毁,解除对上下文的引用,就能安全删除openGLContext而不触发断言。


内容的提问来源于stack exchange,提问作者Chris

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 02:45:56