使用GLEW和Qt 5.x

3

我目前正在尝试使用GLEW实现Qt 5窗口和QOpenGLContext的工作。是的,我知道Qt 5提供了自己的OpenGL函数封装,但由于我的渲染引擎依赖于GLEW并支持其他窗口库,因此Qt内置的内容不是一个选择。

现在,这是我迄今为止得到的结果:

  1. 我子类化了QWindow,并配备了QOpenGLContext。上下文成功初始化。

  2. 在初始化QOpenGLContext之后,我(再次成功)调用glewInit()来初始化GLEW。

  3. 我现在能够以与其他窗口框架(更准确地说是GLFW)完全相同的方式将几何体渲染到默认帧缓冲区中。

这里是棘手的部分:我正在使用OpenGL的uniform buffer objects之一将光数据传输到GPU。一旦我调用glBufferData()进行初始填充,就会出现分段错误。使用基于GLFW的实现和上下文初始化时,一切正常。我知道这种行为对于未经充分初始化的OpenGL上下文可以预期,但是再次设置QOpenGLContext并调用glewInit()似乎非常好用。

这里有一些代码展示了我正在尝试做什么...

QtWindow::QtWindow(QWindow *parent)
 : QWindow(parent) {

  setSurfaceType(QWindow::OpenGLSurface);

  QSurfaceFormat format;
  format.setVersion(4,5);
  format.setOption(QSurfaceFormat::DeprecatedFunctions);
  format.setSwapBehavior(QSurfaceFormat::DoubleBuffer);
  format.setProfile(QSurfaceFormat::CoreProfile);

  setFormat(format);

}

这应该足够后面理解我所需的格式。现在,在第一帧呈现之前,我设置上下文和GLEW...

void QtWindow::init_context() {

  if (!initialized_) {
    context_handler_.init(this);
    initialized_ = true;

    glewExperimental = GL_TRUE;
    auto e = glewInit();
    if (e != GLEW_OK) {
      std::cout << "Failed to initialize glew: " 
                << glewGetErrorString(e) << std::endl;
    }

    glGetError();

  }

}

我使用一个小的辅助类来初始化QOpenGLContext,因为我需要防止Qt取消定义GLEW宏:

void QtContextHandler::init(QWindow* parent) {
  if (!qt_context_) {
    qt_context_ = new QOpenGLContext(parent);
    qt_context_->setFormat(parent->requestedFormat());

    if (qt_context_->create()) {
      auto format(qt_context_->format());
      std::cout << "Initialized Qt OpenGL context "
                << format.majorVersion() << "."
                << format.minorVersion() << " successfully."
                << std::endl;


      qt_context_->makeCurrent(parent);
    } else {
      std::cout << "Failed to initialize Qt OpenGL context!" 
                << std::endl;
    }

  }
}

以下是我设置轻量UBO的步骤,也是OpenGL初始化崩溃时出现的情况。我使用oglplus作为GL包装器,但由于它相当紧密地包装了OpenGL的函数,所以你应该能够理解:

ubo_.Bind(ogl::Buffer::Target::Uniform);

oglplus::Buffer::Data(oglplus::Buffer::Target::Uniform, sizeof(data), &data, oglplus::BufferUsage::DynamicDraw);

有人尝试过类似的方法并能分享他们的经验吗?我会很感激任何帮助,因为我被困在尝试弄清楚自己做错了什么的过程中。再次强调:初始化似乎顺利进行,我甚至能够创建用于渲染网格的VBOs/VAOs/IBOs!只有创建UBO会导致分段错误。
编辑:好的,这里有一些新的见解。首先,如果上传的数据超过一定大小(约90字节),就会发生分段错误。换句话说,我可以使用由Qt创建的上下文渲染仅具有一个自定义光源的场景。但是,当查询GL_MAX_UNIFORM_BLOCK_SIZE时,驱动程序告诉我可用于统一块的64KB(对于由GLFW创建的上下文也是如此)。有人有可能出现问题的想法吗?

1
你说一旦使用glBufferData就会出现段错误。你检查过此时的glBufferData是否为非空吗? - G.M.
@G.M. 是的,我检查过了。有趣的是,我尝试上传一些虚拟数据,例如 std::array<int, 10> d = {0,1,2,3,4,5,6,7,8,9}ogl::Buffer::Data(ogl::Buffer::Target::Uniform, sizeof(d), &d, ogl::BufferUsage::DynamicDraw);,它完美地工作了(除了意外的着色器行为,显然)。我感觉我用于光数据的数据类型被搞乱了或者出了什么问题。 - Felix Lauer
1个回答

2

好的,以防有人遇到类似的困难:我成功地使用glBufferStorage上传UBO数据,而不是使用glBufferData。前者用于创建不可变大小的缓冲区,这对我的目的已经足够了。尽管如此,我仍然不知道glBufferData出了什么问题,是否是Qt中的一个错误或者是我错误地初始化了上下文。


你尝试过在较新版本的Qt上运行吗?(这个帖子是一年前写的,现在已经是2017年了)。 - J.Guarin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接