从上下文共享 QOpenGLWidget 崩溃
crash from context shared QOpenGLWidget
我有两个 QOpenGLWidget
s(view1
, view2
) 作为顶级小部件中的子项。
Qt 文档说 'When multiple QOpenGLWidgets are added as children to the same top-level widget, their contexts will share with each other'。
因此,view1
和 view2
共享 OpenGL 上下文。
我试图渲染在 view1
的上下文中初始化的相同场景,并且应用程序在 view2 的 paintGL()
中崩溃。
我做错了什么?
这是简化的代码:
#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();
}
似乎不应在上下文之间共享顶点状态,即使这些上下文是共享的。
这是固定版本:
#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();
}
据观察,共享顶点属性状态也会导致问题。
我知道我不能通过 OpenGL 规范共享 VAO,但我从未在这里明确使用 VAO。
我不确定这是否被规范禁止或驱动程序错误。
但是,至少在 NVidia 驱动程序上,很明显您不应该在任何情况下共享顶点属性状态,包括共享上下文。
我有两个 QOpenGLWidget
s(view1
, view2
) 作为顶级小部件中的子项。
Qt 文档说 'When multiple QOpenGLWidgets are added as children to the same top-level widget, their contexts will share with each other'。
因此,view1
和 view2
共享 OpenGL 上下文。
我试图渲染在 view1
的上下文中初始化的相同场景,并且应用程序在 view2 的 paintGL()
中崩溃。
我做错了什么?
这是简化的代码:
#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();
}
似乎不应在上下文之间共享顶点状态,即使这些上下文是共享的。
这是固定版本:
#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();
}
据观察,共享顶点属性状态也会导致问题。 我知道我不能通过 OpenGL 规范共享 VAO,但我从未在这里明确使用 VAO。
我不确定这是否被规范禁止或驱动程序错误。 但是,至少在 NVidia 驱动程序上,很明显您不应该在任何情况下共享顶点属性状态,包括共享上下文。