Segfault on glDrawArrays when combining OpenGl and QML

I'm trying to write an application which renders a texture via OpenGL into a QML item. After searching online and trying various things, (felt like a lot of guessing, I have a very limited understanding of OpenGl,) I eventually ran the program through Valgrind and discovered an illegal memory access, meaning I'm not initializing everything needed for the OpenGl to draw correctly. I was hoping someone could look at my rough code and tell me which step I'm forgetting.

I tried to follow and combine the two tutorials in the QT docs, this one (http://doc.qt.io/qt-5/qtquick-scenegraph-openglunderqml-example.html) which shows QML and OpenGl, as well as this one (http://doc.qt.io/qt-5/qtopengl-textures-example.html) which shows how to render a texture using OpenGl and QT. I altered it slightly because my texture was only a 2 dimensional image I wish to display. I was able to successfully follow the latter, rendering my texture to a viewport and drawing it on screen, unfortunately when attempting to integrate QML things went downhill.

My paint function is as follows:

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

        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();
    }

The first line calls intializeGL() if there is no shader program, which is where I believe the issue is. The function is defined as followed:

    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 failedn";
        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 linkn";
        if (!program->bind()) std::cerr << "Error: Program failed to bindn";
        program->setUniformValue("texture", 0);
    }

paint() is a slot connect to the QQuickWindow::beforeRendering signal. Stepping through with a debugger tells me all pointers, (texture, program) are not null when paint() is called. None of the OpenGL calls throw errors, the program simply segfaults in paint() on glDrawArrays.

Thanks!

Edit: further debugging has taught me it is successfully going through the paint function once, it's on the second pass that it fails. However, I never see the fully drawn texture, just the application background is filled in.


绘图函数应该写成如下以保持状态并防止绘图上的段错误:

    if (!program) initializeGL();
    program->bindAttributeLocation("vertex", PROGRAM_VERTEX_ATTRIBUTE);
    program->bindAttributeLocation("texCoord", PROGRAM_TEXCOORD_ATTRIBUTE);
    if (!program->bind()) std::cerr << "Error: Program failed to bindn";
    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();
链接地址: http://www.djcxy.com/p/63884.html

上一篇: QVideoFilterRunnable和OpenGL Context如何协同工作?

下一篇: 合并OpenGl和QML时,在glDrawArrays上的Segfault