Qt5 中屏幕和屏幕外渲染与 QOpenGL\* 类之间的交互

Posted

技术标签:

【中文标题】Qt5 中屏幕和屏幕外渲染与 QOpenGL\\* 类之间的交互【英文标题】:Interactions between Onscreen and Offscreen rendering in Qt5 with QOpenGL\* classesQt5 中屏幕和屏幕外渲染与 QOpenGL\* 类之间的交互 【发布时间】:2016-08-29 08:32:26 【问题描述】:

目标:

通过Qt5 OpenGL框架进行一些onscreenoffscreen渲染,这样资源可以很容易地在两个渲染部分之间共享。具体来说,

渲染工作通过offscreen部分完成(framebuffer可能比显示屏幕大); 屏幕外渲染的结果可以在不同的设置下显示在多个屏幕上部分(例如QOpenGLWidgets),例如不同尺寸,为简单起见; 离屏渲染的结果也可以从 GPU 中提取并保存到QImagecv::Mat 对象中; 上述任务可以异步执行(进行第二次离屏渲染,同时显示或提取第一个离屏结果)。

目前的解决方案:

由于我不知道如何在两个部分之间共享资源,因此在我当前的解决方案中,实际的渲染工作在两个部分中都是冗余完成的:

屏幕上部分: 一个QMainWindow 包含多个QOpenGLWidgetQOpenGLWidget 的子类)对象; 屏幕外部分: 包含QOffscreenSurfaceQOpenGLContextQOpenGLFramebufferObject 指针成员的自定义类以及用于调用OpenGL 函数的QOpenGLFunctions 指针执行实际渲染工作,与this link 非常相似。李> 实际渲染器: 如上所述,实际的渲染工作被提取到一个单独的类中,并且两个部分(onscreenoffscreen)都有自己的句柄。

问题:

有两个QOpenGLContexts:

在后台线程中进行屏幕外工作时(用于异步渲染),它表示基于QWindowQOffscreenSurface不允许存在于gui线程之外; 在主 (GUI) 线程中执行此操作时,它说 QOpenGLContext 无效。

所以我的问题是:

我是否应该在同一个 GUI 线程中执行 offscreenonscreen 工作? 屏幕外屏幕部分之间交流和共享资源的最佳方式是什么?

非常感谢一个简短的实际代码示例做一个简单的渲染工作(例如,通过着色语言绘制一个三角形)。

【问题讨论】:

【参考方案1】:

假设QOpenGLContext *main_ctxQOpenGLWidget 创建的用于实际渲染的上下文,您可以在任何线程中创建另一个上下文ctx 并使其与第一个线程共享纹理和缓冲区:

ctx = std::make_unique<QOpenGLContext>();
ctx->setFormat(main_ctx->format());
ctx->setShareContext(main_ctx);
ctx->create();

我认为QOffscreenSurface 不一定是基于QWindow 的。

offscreen_surface = std::make_unique<QOffscreenSurface>();
offscreen_surface->setFormat(ctx->format());
offscreen_surface->create();
ctx->makeCurrent(offscreen_surface);

然后创建一个QOpenGLFramebufferObject 并从第二个上下文(第二个线程)渲染到它。

然后在主要上下文中使用它的纹理:glBindTexture(GL_TEXTURE_2D, fbo-&gt;texture());。这样做时可能需要一些同步。

【讨论】:

感谢您的帮助。多个 offscreen 部分(在多个线程中),其渲染结果会按照某些规则依次显示在同一个 onscreen 部分中怎么办?他们的ctxs 是否应该共享相同的main_ctx?如果随后使用多个fbos(来自多个屏幕外部分),它们会相互重叠吗?或者多个fbo-&gt;texture()s 会返回相同的值吗?如果有,如何避免?我对fbo的机制和纹理不是很熟悉。 这不像“共享同一个 main_ctx”,因为所有共享上下文具有平等的权利:它们共享共享纹理、着色器和其他 OpenGL 资源。关于 FBO:Qt 似乎为每个 FBO 创建了一个单独的纹理来使用。 再次感谢您的帮助!根据您的建议,我尝试将纹理 ID unit 从 FBO(offscreen 部分)转移到 QOpenGLTextureonscreen 部分),但没有显示所需的纹理。我认为原因可能是不熟悉将QOpenGLTexture 与FBO 一起使用。 Qt5.7的文档说可以渲染TO纹理,也可以渲染WITH纹理。有没有关于这两种用法的简单例子。 (这可能是另一个问题,我应该发布一个新帖子吗?) 提出另一个问题,所以会有一个空间来显示带有QOpenGLFramebufferObject 的代码不起作用。如果该代码是一个足够独立的示例,那么有人可能会修复该代码。 一个新问题 (this link) 已发布。非常感谢!

以上是关于Qt5 中屏幕和屏幕外渲染与 QOpenGL\* 类之间的交互的主要内容,如果未能解决你的问题,请参考以下文章

使用 Docker 使用 QOffscreenSurface 进行屏幕外渲染

是否可以在屏幕外渲染 QWebEnginePage/QWebEngineView?

使用 QOpenGLWidget 进行屏幕外渲染的最简单方法

渲染和 CPU 是不是忽略了屏幕外动画?

CALayer 和屏幕外渲染

UIGestureRecognizer 在屏幕外渲染