cra sh из общего контекста QOpenGLWidget - PullRequest
0 голосов
/ 16 марта 2020

У меня есть два QOpenGLWidget s (view1, view2) в качестве дочерних элементов в виджете верхнего уровня. Документ Qt гласит: «Когда несколько QOpenGLWidget добавляются как дочерние элементы в один и тот же виджет верхнего уровня, их контексты будут делиться друг с другом». Итак, view1 и view2 совместно используют контекст OpenGL. Я попытался отрисовать ту же сцену, которая инициализируется в контексте view1, и приложение вылетает в paintGL() view2. Что я не так?

Вот упрощенный код:

#include <QtGui/QtGui>
#include <QtWidgets/QOpenGLWidget>
#include <QtWidgets/QApplication>
#include <QtWidgets/QHBoxLayout>

static const char *vertexShaderSource =
    "attribute vec4 posAttr;\n"
    "void main() {\n"
    "   gl_Position = posAttr;\n"
    "}\n";

static const char *fragmentShaderSource =
    "void main() {\n"
    "   gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);\n"
    "}\n";

QOpenGLShaderProgram *program = nullptr;
QOpenGLBuffer arrayBuf;
int posAttr = -1;

class View3D : public QOpenGLWidget {
public:
    View3D()
    {
        setMinimumSize(300, 200);
    }
private:
    auto initializeGL() -> void override
    {
        if (program)
            return;

        program = new QOpenGLShaderProgram(this);
        program->addShaderFromSourceCode(QOpenGLShader::Vertex, vertexShaderSource);
        program->addShaderFromSourceCode(QOpenGLShader::Fragment, fragmentShaderSource);
        program->link();
        posAttr = program->attributeLocation("posAttr");

        program->bind();

        GLfloat vertices[] = {
            0.0f, 0.707f, 0.f,
            -0.5f, -0.5f, 0.f,
            0.5f, -0.5f, 0.f,
        };

        arrayBuf.create();
        arrayBuf.bind();
        arrayBuf.allocate(vertices, sizeof(vertices));

        program->enableAttributeArray(posAttr);
        program->setAttributeBuffer(posAttr, GL_FLOAT, 0, 3, 0);

        program->release();
    }

    auto paintGL() -> void override
    {
        auto f = context()->functions();

        const auto dpr = devicePixelRatio();
        f->glViewport(0, 0, width() * dpr, height() * dpr);

        f->glClear(GL_COLOR_BUFFER_BIT);

        program->bind();
        arrayBuf.bind();

        program->enableAttributeArray(posAttr);
        f->glDrawArrays(GL_TRIANGLES, 0, 3);
        program->disableAttributeArray(posAttr);

        arrayBuf.release();
        program->release();
    }

};

auto main(int argc, char **argv) -> int
{
    QApplication app{argc, argv};

    QWidget w;
    auto hbox = new QHBoxLayout{&w};
    hbox->addWidget(new View3D); // view1
    hbox->addWidget(new View3D); // view2
    w.show();

    return app.exec();
}

1 Ответ

0 голосов
/ 19 марта 2020

Кажется, что состояние вершины не должно совместно использоваться контекстами, даже если эти контексты являются общими.

Вот фиксированная версия:

#include <QtGui/QtGui>
#include <QtWidgets/QOpenGLWidget>
#include <QtWidgets/QApplication>
#include <QtWidgets/QHBoxLayout>

static const char *vertexShaderSource =
    "attribute vec4 posAttr;\n"
    "void main() {\n"
    "   gl_Position = posAttr;\n"
    "}\n";

static const char *fragmentShaderSource =
    "void main() {\n"
    "   gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);\n"
    "}\n";

QOpenGLBuffer *arrayBuf = nullptr;
QOpenGLShaderProgram *program = nullptr;

class View3D : public QOpenGLWidget {
public:
    View3D()
    {
        setMinimumSize(300, 200);
    }
private:
    int posAttr = -1;
    auto initializeGL() -> void override
    {
        if (!arrayBuf) {
            arrayBuf = new QOpenGLBuffer;
            arrayBuf->create();
            arrayBuf->bind();
            GLfloat vertices[] = {
                0.0f, 0.707f, 0.f,
                -0.5f, -0.5f, 0.f,
                0.5f, -0.5f, 0.f,
            };
            arrayBuf->allocate(vertices, sizeof(vertices));
        }

        if (!program) {
            program = new QOpenGLShaderProgram(this);
            program->addShaderFromSourceCode(QOpenGLShader::Vertex, vertexShaderSource);
            program->addShaderFromSourceCode(QOpenGLShader::Fragment, fragmentShaderSource);
            program->link();
        }

        posAttr = program->attributeLocation("posAttr");
        program->bind();
        arrayBuf->bind();
        program->enableAttributeArray(posAttr);
        program->setAttributeBuffer(posAttr, GL_FLOAT, 0, 3, 0);
        program->release();
    }

    auto paintGL() -> void override
    {
        auto f = context()->functions();

        const auto dpr = devicePixelRatio();
        f->glViewport(0, 0, width() * dpr, height() * dpr);

        f->glClear(GL_COLOR_BUFFER_BIT);

        program->bind();
        arrayBuf->bind();

        program->enableAttributeArray(posAttr);
        f->glDrawArrays(GL_TRIANGLES, 0, 3);
        program->disableAttributeArray(posAttr);

        arrayBuf->release();
        program->release();
    }

};

auto main(int argc, char **argv) -> int
{
    QApplication app{argc, argv};

    QWidget w;
    auto hbox = new QHBoxLayout{&w};
    hbox->addWidget(new View3D); // view1
    hbox->addWidget(new View3D); // view2
    w.show();

    return app.exec();
}

Из наблюдения, совместное использование состояния атрибута вершины также может привести к проблема. Я знал, что не могу поделиться VAO по спецификации OpenGL, но я никогда не использовал VAO явно здесь.

Я не уверен, что это запрещено спецификацией или ошибкой драйвера. Однако, по крайней мере, в драйвере NVidia очевидно, что вы не должны совместно использовать состояние атрибута вершины для любых случаев, включая общие контексты.

...