C++ 无头QT4 OpenGL应用程序
我正在QT4中创建一个headless控制台应用程序,该应用程序执行一些OpenGL渲染,然后通过websocket将结果通过网络发送出去。我已经运行了所有的渲染和网络代码(假设我有一个GUI),但是我在转换到无头应用程序时遇到了一些问题。是否可以在没有窗口的情况下创建QGLContext 在网上阅读的机会不多,但根据我收集的信息,你可以创建一个QGLPixelBuffer,它是一个有效的QPaintDevice。它似乎创建了自己的专用QGLContext,用于硬件加速绘图。这个路由的问题是,我需要访问它的底层QGLContext,这样我就可以与另一个线程(用于从渲染场景中快速DMA纹理传输的网络线程)共享它。下面是一个小型原型。有什么想法吗 应用程序.hC++ 无头QT4 OpenGL应用程序,c++,qt,opengl,C++,Qt,Opengl,我正在QT4中创建一个headless控制台应用程序,该应用程序执行一些OpenGL渲染,然后通过websocket将结果通过网络发送出去。我已经运行了所有的渲染和网络代码(假设我有一个GUI),但是我在转换到无头应用程序时遇到了一些问题。是否可以在没有窗口的情况下创建QGLContext 在网上阅读的机会不多,但根据我收集的信息,你可以创建一个QGLPixelBuffer,它是一个有效的QPaintDevice。它似乎创建了自己的专用QGLContext,用于硬件加速绘图。这个路由的问题是,我
/**
@file
@author Nikolaus Karpinsky
*/
#ifndef _APPLICATION_H_
#define _APPLICATION_H_
#include <QCoreApplication>
#include <QTimer>
#include "MainController.h"
#endif // _APPLICATION_H_
主控制器
/**
@file
@author Nikolaus Karpinsky
*/
#ifndef _MAIN_CONTROLLER_H_
#define _MAIN_CONTROLLER_H_
#include <QObject>
#include <QGLWidget>
#include <QGLPixelBuffer>
#include <QGLFramebufferObject>
#include <memory>
using namespace std;
class MainController : public QObject
{
Q_OBJECT
private:
unqiue_ptr<QGLPixelBuffer> m_mainBuffer;
//unique_ptr<QGLContext> m_mainContext;
public:
MainController();
void Init(void);
public slots:
void Start(void);
void Close(void);
signals:
void Finished(void);
};
#endif // _MAIN_CONTROLLER_H_
/**
@文件
@作家尼古拉斯·卡尔平斯基
*/
#ifndef\u主控制器\u H_
#定义主控制器_
#包括
#包括
#包括
#包括
#包括
使用名称空间std;
类主控制器:公共QObject
{
Q_对象
私人:
unqiue_ptr m_main buffer;
//唯一的主上下文;
公众:
主控制器();
void Init(void);
公众时段:
作废开始(作废);
作废关闭(作废);
信号:
完成作废(作废);
};
#endif/\u主控制器\u H_
MainController.cpp
#include "MainController.h"
MainController::MainController() : QObject()
{ }
void MainController::Init(void)
{
m_mainBuffer = unique_ptr<QGLPixelBuffer>(new QGLPixelBuffer(800, 600));
bool has = buffer->hasOpenGLPbuffers();
bool current = buffer->makeCurrent();
bool valid = buffer->isValid();
// Now I need to get access to the context to share it with additional threads
// m_mainContext = unique_ptr<QGLContext>(new QGLContext(buffer.getContext()));
}
void MainController::Start(void)
{
}
void MainController::Close(void)
{
// This will tell the event loop that we are done and close the app
emit( Finished() );
}
#包括“MainController.h”
MainController::MainController():QObject()
{ }
void MainController::Init(void)
{
m_mainBuffer=unique_ptr(新的QGLPixelBuffer(800600));
bool has=buffer->hasOpenGLPbuffers();
bool current=buffer->makeCurrent();
bool valid=buffer->isValid();
//现在我需要访问上下文以与其他线程共享它
//m_mainContext=unique_ptr(新的QGLContext(buffer.getContext());
}
void主控制器::开始(void)
{
}
void主控制器::关闭(void)
{
//这将告诉事件循环我们已经完成并关闭应用程序
发射(完成的());
}
是否可以在没有窗口的情况下创建QGLContext
是的,但是有一个陷阱
在网上阅读的机会不多,但根据我收集的信息,你可以创建一个QGLPixelBuffer,它是一个有效的QPaintDevice
是的,但是那个PBuffer还需要和GPU通话。在Linux中,与GPU通信的通常方式是通过X服务器。因此,您实际上需要一台X服务器,使用GPU驱动程序,启动和活动VT,以便PBuffer可以在GPU上工作
希望不久GPU将有一个新的ABI/API,它允许您在GPU上创建屏幕外渲染上下文,而无需X服务器
这个路由的问题是,我需要访问它的底层QGLContext,这样我就可以与另一个线程(用于从渲染场景中快速DMA纹理传输的网络线程)共享它
不幸的是,Qt开发人员对OpenGL的了解似乎很有限。有几件事在OpenGL中是完全可能的,并且在Qt中是不可能的,没有明显的原因。例如,您可以使用一个可绘制文件拥有任意数量的上下文。但是,您也可以通过重新绑定单个上下文来对任意数量的(兼容的)绘图表使用单个上下文。Qt和一个明显的设计缺陷都不支持这两种方法。我现在自己也在努力解决这个问题。好的,所以经过一番尝试后,我找到了一个足够好的解决方案。目前,我正在以QApplication vs QCoreApplication的形式运行我的应用程序。从这里,我在GUI线程上创建了一个QGLWidget,然后立即在创建和初始化OpenGL上下文的小部件上调用updateGL()。假设我从未使应用程序可见,它运行“headless”,但仍然从X或Explorer获得所需的QT窗口句柄 再深入一点,我还需要在其他线程上共享QGLContext。要从QGLWidget复制上下文,我只需使用不推荐使用的构造函数创建一个QGLWidget,您可以在其中指定一个画师(QGLWidget),然后使用QGLWidgets上下文创建。我在下面贴了一个例子来说明。使用这个,我可以在一个线程中编写纹理,在另一个线程中处理,同时保持应用程序“无头”。谢谢datenwolf的帮助
shared_ptr<QGLContext> MainController::MakeSharedContext(void)
{
shared_ptr<QGLContext> sharedContext(nullptr);
if(nullptr != m_mainContext)
{
// m_mainContext is: shared_ptr<QGLWidget>
sharedContext = shared_ptr<QGLContext>( new QGLContext(m_mainContext->format(), m_mainContext.get( ) ) );
bool created = sharedContext->create( m_mainContext->context( ) );
Utils::AssertOrThrowIfFalse(created, "Unable to create a shared OpenGL context" );
}
return sharedContext;
}
shared\ptr MainController::MakeSharedContext(无效)
{
共享内容(nullptr);
if(nullptr!=m_mainContext)
{
//m_main上下文为:共享\u ptr
sharedContext=shared_ptr(新的QGLContext(m_mainContext->format(),m_mainContext.get());
bool created=sharedContext->create(m_mainContext->context());
Utils::AssertOrThrowIfFalse(创建时,“无法创建共享OpenGL上下文”);
}
返回共享上下文;
}
Hmmm,糟糕透了。我希望重用我们已经拥有的许多使用QT的组件。我可以忍受必须运行X会话,但我需要在多个线程之间共享上下文。我有单线程屏幕外(控制台应用程序)渲染(假设我有一个X会话),但我不确定如何在两个应用程序之间共享纹理threads@Nik:基本上和我现在遇到的问题一样。我曾考虑将我自己的Qt-OpenGL基础设施整合起来,但看看问题有多严重,我想我会在Qt-dev论坛上对此大发雷霆。
shared_ptr<QGLContext> MainController::MakeSharedContext(void)
{
shared_ptr<QGLContext> sharedContext(nullptr);
if(nullptr != m_mainContext)
{
// m_mainContext is: shared_ptr<QGLWidget>
sharedContext = shared_ptr<QGLContext>( new QGLContext(m_mainContext->format(), m_mainContext.get( ) ) );
bool created = sharedContext->create( m_mainContext->context( ) );
Utils::AssertOrThrowIfFalse(created, "Unable to create a shared OpenGL context" );
}
return sharedContext;
}