0

I have two QOpenGLWidgets(view1, view2)as children in a top-level widget. Qt document says 'When multiple QOpenGLWidgets are added as children to the same top-level widget, their contexts will share with each other'. So, view1 and view2 share OpenGL context. I have tried to render same scene which is initialized in view1's context and the application crashes in view2's paintGL(). What did I wrong?

Here's simplified code:

#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();
}
asked Mar 16, 2020 at 7:44

1 Answer 1

0

It seems that vertex state shall not be shared between contexts even though those contexts are shared.

Here's fixed version:

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

From observation, sharing vertex attribute state also can cause problem. I knew that I cannot share VAO by OpenGL specification, but I never used VAO explictily here.

I am not sure that this is inhibited by specification or a bug of driver. However, at least on NVidia driver, it is obvious that you should not share vertex attribute state for any cases including shared contexts.

answered Mar 19, 2020 at 6:58
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.