【问题标题】:Segfault on glDrawArrays when combining OpenGl and QML结合 OpenGL 和 QML 时 glDrawArrays 上的段错误
【发布时间】:2017-07-04 19:51:55
【问题描述】:

我正在尝试编写一个通过 OpenGL 将纹理渲染到 QML 项目中的应用程序。在网上搜索并尝试了各种事情之后,(感觉像很多猜测,我对 OpenGl 的了解非常有限)我最终通过 Valgrind 运行程序并发现了非法内存访问,这意味着我没有初始化所有需要的东西OpenGL 正确绘制。我希望有人可以查看我的粗略代码并告诉我我忘记了哪一步。

我尝试遵循并结合 QT 文档中的两个教程,这个 (http://doc.qt.io/qt-5/qtquick-scenegraph-openglunderqml-example.html) 显示了 QML 和 OpenGl,以及这个 (http://doc.qt.io/qt-5/qtopengl-textures-example.html) 显示了如何使用 OpenGl 和QT。我稍微改变了它,因为我的纹理只是我希望显示的二维图像。我能够成功地遵循后者,将我的纹理渲染到视口并将其绘制在屏幕上,不幸的是,当尝试集成 QML 时,事情就走下坡路了。

我的paint函数如下:

    void glViewer::paint()
    {
        // program is type QOpenGLShaderProgram *
        if (!program) initializeGL();
        if (!program->bind()) std::cerr << "Error: Program failed to bind\n";

        glViewport(0, 0, _viewportSize.width(), _viewportSize.height());
        glClearColor(clearColor.redF(), clearColor.greenF(), clearColor.blackF(), clearColor.alphaF());
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        QMatrix4x4 m;
        m.ortho(0.0f, 1.0f, 1.0f, 0.0f, 4.0f, 15.0f);
        m.translate(0.0f, 0.0f, -10.0f);
        program->setUniformValue("matrix", m);

        program->enableAttributeArray(PROGRAM_VERTEX_ATTRIBUTE);
        program->enableAttributeArray(PROGRAM_TEXCOORD_ATTRIBUTE);

        program->setAttributeBuffer(PROGRAM_VERTEX_ATTRIBUTE, GL_FLOAT, 0, 3, 5 * sizeof(GLfloat));
        program->setAttributeBuffer(PROGRAM_TEXCOORD_ATTRIBUTE, GL_FLOAT, 3 * sizeof(GLfloat), 2, 5 * sizeof(GLfloat));

        texture->bind();

        glDrawArrays(GL_TRIANGLE_FAN, 0, 4);

        program->disableAttributeArray(PROGRAM_VERTEX_ATTRIBUTE);
        program->disableAttributeArray(PROGRAM_TEXCOORD_ATTRIBUTE);
        program->release();
        // _window refers the QQuickWindow generated by the QApplication
        _window->resetOpenGLState();
    }

如果没有着色器程序,第一行调用 intializeGL(),我认为这就是问题所在。函数定义如下:

    void glViewer::initializeGL()
    {
        initializeOpenGLFunctions();

        texture = new QOpenGLTexture(QOpenGLTexture::Target2D);
        texture->setSize(imageDisplayResolution.x,imageDisplayResolution.y,1);
        texture->setMinMagFilters(QOpenGLTexture::Nearest, QOpenGLTexture::Nearest);
        texture->setWrapMode(QOpenGLTexture::ClampToBorder);
        texture->setFormat(QOpenGLTexture::TextureFormat::R32F);
        texture->allocateStorage(QOpenGLTexture::Luminance, QOpenGLTexture::Float32);
        if (!texture->isStorageAllocated()) std::cerr << "Error: Failed to allocate texture!\n";

        QVector<GLfloat> vertData;

        // vertex position 
        vertData.append(0);
        vertData.append(0);
        vertData.append(0);
        // texture coordinate
        vertData.append(0);
        vertData.append(0);

        // vertex position 
        vertData.append(0);
        vertData.append(1);
        vertData.append(0);
        // texture coordinate
        vertData.append(0);
        vertData.append(1);

        // vertex position 
        vertData.append(1);
        vertData.append(1);
        vertData.append(0);
        // texture coordinate
        vertData.append(1);
        vertData.append(1);

        // vertex position 
        vertData.append(1);
        vertData.append(0);
        vertData.append(0);
        // texture coordinate
        vertData.append(1);
        vertData.append(0);

        vbo.create();
        if (!vbo.bind()) std::cerr << "Error: VBO bind has failed\n";
        vbo.allocate(vertData.constData(), vertData.count() * sizeof(GLfloat));

        // Enable or disable server-side GL capabilities.
        glEnable(GL_DEPTH_TEST);
        glEnable(GL_CULL_FACE);

    #define PROGRAM_VERTEX_ATTRIBUTE 0
    #define PROGRAM_TEXCOORD_ATTRIBUTE 1

        program = new QOpenGLShaderProgram;
        if (!program->addShaderFromSourceCode(QOpenGLShader::Vertex,
                                       "attribute highp vec4 vertex;\n"
                                        "attribute mediump vec4 texCoord;\n"
                                        "varying mediump vec4 texc;\n"
                                        "uniform mediump mat4 matrix;\n"
                                        "void main(void)\n"
                                        "{\n"
                                        "    gl_Position = matrix * vertex;\n"
                                        "    texc = texCoord;\n"
                                        "}\n")) { std::cerr << "Error: Vertex shader failed to compile!\n"; }
        if (!program->addShaderFromSourceCode(QOpenGLShader::Fragment,
                                       "uniform sampler2D texture;\n"
                                        "varying mediump vec4 texc;\n"
                                        "void main(void)\n"
                                        "{\n"
                                        "    gl_FragColor = texture2D(texture, texc.st).rrra;\n"
                                        "}\n")) { std::cerr << "Error: Fragment shader failed to compile!\n"; }
        // Binds the attribute name to the specified location.
        program->bindAttributeLocation("vertex", PROGRAM_VERTEX_ATTRIBUTE);
        program->bindAttributeLocation("texCoord", PROGRAM_TEXCOORD_ATTRIBUTE);

        if (!program->link()) std::cerr << "Error: Program shaders failed to link\n";
        if (!program->bind()) std::cerr << "Error: Program failed to bind\n";
        program->setUniformValue("texture", 0);
    }

paint() 是连接到 QQuickWindow::beforeRendering 信号的插槽。使用调试器单步执行会告诉我所有指针(纹理、程序)在调用paint() 时都不为空。所有的 OpenGL 调用都不会引发错误,程序只是在 glDrawArrays 上的 paint() 中出现段错误。

谢谢!

编辑:进一步的调试告诉我它成功地通过了一次绘画功能,它在第二次失败时失败了。但是,我从来没有看到完全绘制的纹理,只是填充了应用程序背景。

【问题讨论】:

    标签: c++ qt opengl qml


    【解决方案1】:

    paint函数应该写成这样,以保持状态并防止绘图时出现段错误:

        if (!program) initializeGL();
        program->bindAttributeLocation("vertex", PROGRAM_VERTEX_ATTRIBUTE);
        program->bindAttributeLocation("texCoord", PROGRAM_TEXCOORD_ATTRIBUTE);
        if (!program->bind()) std::cerr << "Error: Program failed to bind\n";
        texture->bind();
        vbo.bind();
    
        glClearColor(_clearColor.redF(), _clearColor.greenF(), _clearColor.blackF(), _clearColor.alphaF());
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        glViewport(viewportPosition.x(), viewportPosition.y(), viewportSize.width(), viewportSize.height());
    
        QMatrix4x4 m;
        m.ortho(0.0f, 1.0f, 1.0f, 0.0f, 4.0f, 15.0f);
        m.translate(0.0f, 0.0f, -10.0f);
        program->setUniformValue("matrix", m);
        program->setUniformValue("texture", 0);
    
        program->enableAttributeArray(PROGRAM_VERTEX_ATTRIBUTE);
        program->enableAttributeArray(PROGRAM_TEXCOORD_ATTRIBUTE);
        program->setAttributeBuffer(PROGRAM_VERTEX_ATTRIBUTE, GL_FLOAT, 0, 3, 5 * sizeof(GLfloat));
        program->setAttributeBuffer(PROGRAM_TEXCOORD_ATTRIBUTE, GL_FLOAT, 3 * sizeof(GLfloat), 2, 5 * sizeof(GLfloat));
    
        glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
    
        program->disableAttributeArray(PROGRAM_VERTEX_ATTRIBUTE);
        program->disableAttributeArray(PROGRAM_TEXCOORD_ATTRIBUTE);
        program->disableAttributeArray(0);
        program->release();
        texture->release();
        vbo.release();
        _window->resetOpenGLState();
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多