首页 > 解决方案 > 从不同线程访问的 Qt OpenGL FrameBufferObject 纹理

问题描述

我有一个使用 QOpenGLWidget 的 qt 应用程序。这有一个从 QThread 子类化的线程,它的工作是获取解码的视频帧并根据它们的 alpha 值将它们混合在一起。这是通过在主线程上创建并使用 QThread::moveToThread 传递到 QThread 的辅助上下文来完成的。此外,QOpenGLWidget 上下文和辅助上下文是共享的,我检查它们是否实际上是共享的。它使用 QOffscreenSurface(也在主线程中创建)和在辅助线程中绘制的 QOpenGLFrameBufferObject。我可以将该帧缓冲区对象转换为图像并保存它,这正是我所期望的。然后我打电话给:

    m_context->functions()->glActiveTexture(GL_TEXTURE0 + 12);
    m_context->functions()->glBindTexture(GL_TEXTURE_2D, m_fbo->texture());

这是希望我可以打电话

    m_program->setUniformValue("onscreenTexture", 12);

在我的主 Gui 线程 Draw 函数中,该纹理将可以访问。当我在主 GUI 上重新创建它并绘制到 fbo 然后绑定 fbo 纹理然后使用不同的着色器在该纹理槽处绘制采样器值时,这将起作用。我知道有很多人只是盲目地评论发布代码,但它非常冗长,我希望也许有人能发现我遗漏的一些明显的东西。看来我应该能够:

  1. 在主线程上创建第二个上下文和屏幕外表面
  2. 将它们传递给辅助线程并将屏幕外绘图处理到 FBO
  3. 将该 FBO 纹理绑定到指定的纹理槽
  4. 使用与 FBO 绑定到的插槽相关联的主线程上的着色器绘制该纹理插槽中的内容。

但百万美元的问题是为什么我不能在主线程中获得 FBO 纹理数据。我可以将辅助线程中的 FBO 纹理数据作为图像获取,我可以通过绑定它并将其与第二个着色器一起使用来获取主线程上的 FBO 纹理数据,但我似乎无法将其全部完成单独的线程。这些是绘制到 FBO 的主线程函数和着色器,这很有效。FBO 将发布正确的图像。

void VideoPanel::RunTextureThread()
{
    m_terminateThread = false;
    if (m_textureThread.get() && m_textureThread->isRunning())
        return;

    m_context->moveToThread(m_textureThread.get());
    m_textureThread->start();
}

void TextureThread::run()
{
    Initialize();

    while (!QThread::currentThread()->isInterruptionRequested())
    {
        while (!m_mutex->try_lock());
        m_context->makeCurrent(m_surface);

        if (m_gObj->LoadNextTexture())
        {
            m_fbo->bind();
            m_context->functions()->glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
            m_context->functions()->glEnable(GL_BLEND);
            m_context->functions()->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
            m_gObj->Draw();
            m_fbo->release();

            m_context->functions()->glActiveTexture(GL_TEXTURE0 + 12);
            m_context->functions()->glBindTexture(GL_TEXTURE_2D, m_fbo->texture());
        }

        m_context->doneCurrent();
        m_mutex->unlock();
    }
}

#version 440

in vec2 TexCoords;
uniform sampler2D diffuseTexture[8];
uniform float alphas[8];
uniform int count;

void main()
{
    vec4 firstColor = texture2D(diffuseTexture[0], TexCoords);
    float firstAlpha = alphas[0];
    firstColor.a = firstAlpha;
    vec4 outputColor = firstColor;

    for(int i = 1; i < count; ++i)
    {
        vec4 nextColor = texture2D(diffuseTexture[i], TexCoords);
        float nextAlpha = alphas[i];
        float combinedAlpha = firstAlpha + (nextAlpha * (1.0 - firstAlpha));
        outputColor = vec4((firstColor.rgb * firstAlpha) + (nextColor.rgb * nextAlpha * (1.0 - firstAlpha)), combinedAlpha);
        firstColor = outputColor;
        firstAlpha = combinedAlpha;
    }

    gl_FragColor = outputColor;
}

这是我设置的主要 Gui 线程着色器

void OnscreenGraphicsObject::BindToDraw()
{
    if (!m_program)
        return;
    m_program->bind();

    glActiveTexture(GL_TEXTURE0 + 12);
    m_program->setUniformValue("onscreenTexture", 12);
    m_vao.bind();
}

#version 440

in vec2 TexCoords;
uniform sampler2D onscreenTexture;

void main()
{
    gl_FragColor = texture2D(onscreenTexture, TexCoords);
}

我确定这是我忽略的一些愚蠢的事情,但此时我正在用头撞墙。我查看了所有文档,似乎共享上下文应该使这个 FBO 纹理跨线程可用

标签: qtopengl

解决方案


推荐阅读