I'm working on creating a headless console application in QT4 that does some OpenGL rendering and then ships the result out across the network via a websocket. I have all of the rendering and network code running (assuming that I have a GUI), but I am having some trouble transitioning to a headless application. Is it possible to create a QGLContext without having a window?
Reading on the web hasn't turned up much, but from what I have gathered you can create a QGLPixelBuffer which is a valid QPaintDevice. It seems to create its own private QGLContext that it uses for hardware accelerated drawing. The problem that I am having with this route is that I need access to it's underlying QGLContext so that I can share it with another thread (network thread for fast DMA texture transfers out of the rendered scene). Included below is a small prototype. Any ideas?
Application.h
/**
#file
#author Nikolaus Karpinsky
*/
#ifndef _APPLICATION_H_
#define _APPLICATION_H_
#include <QCoreApplication>
#include <QTimer>
#include "MainController.h"
#endif // _APPLICATION_H_
Application.cpp
#include "Application.h"
int main(int argc, char **argv)
{
// Setup our console application with an event loop
QCoreApplication app(argc, argv);
// Create and initialize our controller
MainController controller;
controller.Init();
QObject::connect(&controller, SIGNAL( Finished() ), &app, SLOT( quit() ), Qt::QueuedConnection);
// This will put start on top of the event loop
QTimer::singleShot(0, &controller, SLOT( Start() ));
// Finally start up the event loop
return app.exec();
}
MainController.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_
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() );
}
Is it possible to create a QGLContext without having a window?
Yes, but there is a catch…
Reading on the web hasn't turned up much, but from what I have gathered you can create a QGLPixelBuffer which is a valid QPaintDevice.
Yes, but that PBuffer still needs to talk to the GPU. And in Linux the usual way to talk to the GPU is through the X server. So you actually need an X server, using the GPUs drivers, to be launched and the active VT so that a PBuffer can work on the GPU.
Hopefully there will be a new ABI/API to GPUs soon, that allows you to create offscreen render contexts on a GPU without having an X server around.
The problem that I am having with this route is that I need access to it's underlying QGLContext so that I can share it with another thread (network thread for fast DMA texture transfers out of the rendered scene).
Unfortunately the Qt developers have only limited knowledge about OpenGL, as it seems. Several things that are perfectly possible with OpenGL and well specified are not possible with Qt for no apparent reason. For example you can have an arbitrary number of contexts using a single drawable. But you can also use single context on an arbitrary number of (compatible) drawables by rebinding it. Neither is supported by Qt and a clear design flaw. I'm struggling with this myself right now.
Ok, so after some playing around I found a good enough solution. Currently I am running my application as a QApplication vs QCoreApplication. From here I create a QGLWidget on the GUI thread and then immediately call updateGL() on the widget which creates and initalizes the OpenGL context. Assuming I don't ever make the app visible it runs "headless" but still gets the QT needed window handle from X or Explorer.
Going a bit deeper, I also needed to get shared QGLContexts on other threads. To make copies of the context from the QGLWidget I simply create a QGLWidget using the deprecated constructor where you can specify a painter (QGLWidget) and then create using the QGLWidgets context. I posted an example below to show. Using this I can write textures in one thread and process in another while keeping the app "headless". Thanks for the help 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;
}
Related
I'm working on an application that involves using real time, continuous, audio input, for which I'm using portaudio. I created simple cli version first in order to set things up and the memory usage in the cli version seemed fine. In the CLI version, while the recording was on, no extra memory was being allocated aside from the initial buffer.
However, in the process of applying the same code from the CLI to a GUI (for which, I'm using Qt), I notice that as the recording proceeds, the memory being used by the application constantly increases (by about 3 mb/sec). Since my application involves audio input for an undefined amount of time, such behaviour can be extremely fatal and thus,I started stripping off segments from the code inorder to check which area was responsible for this memory being used. (note that this behavior was NOT being observed from the cli version, and that nearly the same code was used in qt, aside from the addition of a Q_OBJECT macro)
I tried this for a while but could not find anything.
I am relatively new to using Qt and would greatly appreciate some help with this
My widget apps header file
#ifndef DETECTORMAIN_H
#define DETECTORMAIN_H
#include <QMainWindow>
#include <QThread>
#include <QPointer>
#include "utils/rectools.h" /*Custom header file, the implementation of
which has been carried over from the cli version
which worked with constant memory usage.
Contains a class Recorder with the Q_OBJECT macro*/
QT_BEGIN_NAMESPACE
namespace Ui { class detectorMain; }
QT_END_NAMESPACE
class detectorMain : public QMainWindow
{
Q_OBJECT
public:
detectorMain(QWidget *parent = nullptr);
~detectorMain();
private slots:
void on_beginRecordingButton_clicked();
void on_stopRecordingButton_clicked();
void updateVolLabel(std::string);
private:
Ui::detectorMain *ui;
QPointer<Recorder> recorder;
QThread* thread;
};
#endif // DETECTORMAIN_H
Source file
#include "detectormain.h"
#include "ui_detectormain.h"
detectorMain::detectorMain(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::detectorMain)
{
ui->setupUi(this);
recorder = new Recorder;
thread = new QThread;
recorder->moveToThread(thread);
thread->start();
ui->beginRecordingButton->setEnabled(true);
ui->stopRecordingButton->setEnabled(false);
connect(recorder, SIGNAL(UpdateVols(std::string)), this, SLOT(updateVolLabel(std::string)));
}
detectorMain::~detectorMain()
{
delete ui;
}
void detectorMain::on_beginRecordingButton_clicked()
{
ui->beginRecordingButton->setEnabled(false);
ui->stopRecordingButton->setEnabled(true);
recorder->begin_recording();
}
void detectorMain::on_stopRecordingButton_clicked()
{
recorder->stop_recording();
ui->beginRecordingButton->setEnabled(true);
ui->stopRecordingButton->setEnabled(false);
}
void detectorMain::updateVolLabel(std::string vol)
{
ui->VolLabel->setText(QString::fromStdString(vol));
QCoreApplication::processEvents();
}
The function Recorder::begin_recording() emits UpdateVols(std::string) where UpdateVols is a signal in the Recorder class. It emits at a pretty fast rate (around 1 every ms). Does this have something to with the memory usage increasing?
In the CLI version I could just cout whatever I needed to and this is the most major difference in code between the CLI version and the Qt version.
The memory usage does not reduce after the begin_recording() function has finished execution though which confuses me.
For example, the app starts at 9 mb memory usage, increases to about 39 when begin_recording() runs for 10 seconds, and stays at 39mb when not doing anything afterwards.
If it was the fast emit rate, I assume that the memory usage will return to normal when it is no longer emitting.
Additionally, in the above code, when the beginRecordingButton is clicked, the app becomes unresponsive, but resumes once the function recorder->begin_recording() has finished execution. I guess this has something to do with the memory increasing constantly but I'm not too sure.
I believe the error to lie somewhere in how I'm using the QThread object and moving the recorder object to it, but I'm not sure how to fix it.
In the process of finding out where the memory usage was being increased, I tried running a bare app with just the buttons and labels, not involving the recorder class at all. On simply opening this app with zero functionality, the memory usage kept increasing by about 0.5mb whenever it showed a non zero CPU utilization. After increasing, it does not fall down even if the cpu utilisation was 0.
Overall, I would like to ask,
1)How can I fix the issue of the memory usage constantly increasing? (I don't think the error lies in the Recorder class as the same code runs without qt at constant memory)
2)Is the behavior mentioned in the final paragraph normal?
What #G.M. said in the comments worked. Thank You
The problem was the emit rate. 1khz is too fast and a lot gets build up.
What is a good way to create application with multiple windows in Qt? Something like GIMP. I have already read this answer and it is not what I need.
I have two windows, one with controls and one with OpenGL inside. Right now I have something like this:
int main()
{
// some code
MainWindow mw;
mw.show();
GLWindow gw;
gw.show();
// ...
}
I don't like this for two reasons. First reason is when I start my application, window with OpenGL will be on top (because it is last to call show()) but MainWindow will be buried somewhere under all opened windows. What I need is both windows in front of everything (like GIMP), preferably with focus on MainWindow (I guess I can bring them to front, so that is minor issue). Second reason I don't like this is that my application will be closed completely only when I close both windows.
So I was thinking of having a reference to GLWindow inside MainWindow, and creating it from MainWindow.
Would that be a good way to create application with several windows?
EDIT: GLWindow inherits from QOpenGLWindow.
You are doing right, but with the following simple tricks, you can resolve both issues that cause you do not like your right method:
To activate both windows, just do as follows:
MainWindow mw;
mw.show();
mw.activateWindow();
GLWindow gw;
gw.show();
gw.activateWindow();
To resolve the quit problem, you have to override the closeEvent in both windows. To do that, add the following code into the header file of your both windows:
protected:
void closeEvent(QCloseEvent *event) override;
and in the implementation of the closeEvent, just write qApp->quit();. This way once you close either window, your application will terminate completely.
MainWindow.cpp
void MainWindow::closeEvent(QCloseEvent *event)
{
qApp->quit();
}
and
GLWindow.cpp
void GLWindow::closeEvent(QCloseEvent *event)
{
qApp->quit();
}
I'm not sure I completely understand the situation but, typically, you can make the 'secondary' widgets child dialogs of the QMainWindow. Given your example code that would be something like...
int main ()
{
// some code
MainWindow mw;
mw.show();
/*
* Secondary windows should be created with the QMainWindow mw
* as their parent.
*/
GLWindow gw(&mw);
/*
* Set the Qt::Dlaog window flag to `encourage' the QMainWindow
* and its children to behave as a group.
*/
gw.setWindowFlags(gw.windowFlags() | Qt::Dialog);
gw.show();
// ...
}
Now all widgets behave as a group (possibly subject to the window manager being used) and closing the QMainWindow will, by default, close the application.
I am going to make a thread which recieves the image from webcam camera, using opencv and Mat type. then I convert it to QImage and send it to main thread using a signal. when I want to visualize it in a QLabel object in ui (after converting to a pixmap) I get this error:
The program has unexpectedly finished.
here is my camera class:
camera.h:
#ifndef CAMERA_H
#define CAMERA_H
#include <QObject>
#include <QThread>
#include <QtCore>
#include <QtGui>
#include <opencv2/opencv.hpp>
using namespace cv;
class Camera: public QThread
{
Q_OBJECT
public:
Camera();
void run();
bool Stop = false;
signals:
void ImgSignal(QImage*);
private:
public slots:
};
#endif // THREAD_H
camera.cpp:
#include "camera.h"
#include <iostream>
using namespace std;
Camera::Camera()
{
}
void Camera::run()
{
VideoCapture cap;
cap.open(0);
while(1){
Mat img;
cap >> img;
cvtColor(img,img,CV_BGR2RGB);
QImage image = QImage((const uchar*)img.data,img.cols,img.rows,img.step,QImage::Format_RGB888);
emit ImgSignal(&image);
QThread::msleep(30);
}
}
and finally my onImgSignal function that recieves the image and passes it to gui:
void MainWindow::onImgSignal(QImage *img)
{
QPixmap *p;
p->fromImage(*img);
ui->label->setPixmap(*p);
}
I would be so glad if you help me. thanks!
Edit
when I changed the pixmap poiner to a pixmap variable the error did not come up but the pixmap variable is null. even if i load an image separately it will be null:
QPixmap p;
p.load("mark.png");
cout << p.isNull();
ui->label->setPixmap(p);
My first hunch is that some pointer to some object/memory are accidentally accessed by two different threads at the same time, creating an access violation. So by just making a COPY of the image you pass around might do the trick (so both threads arn't accessing the pixel data of the same image at the same time). Here are some other things you can do to address that:
First, the threads implementation in Qt is a bit unconventional. For example, it is not considered best practice to extend the QThread class like you have done, as the QThread instance will NOT live in the new OS level thread. Yes! It's true. This leads to many sources of confusion that in turn lead to bugs. To read the official unofficial guide on how to do threads correctly in Qt, please look at this excellent article. Short summary: QThread class will act as a "management" class living in the execution thread where you instantiated it, so first tip is to learn this, and use the QThread class as intended.
Second, Qt is supposed to guess during signal time when the source and destination are in same thread or not, however I have found that it sometimes, just for the peace of mind, pays to be specific about how signals will be passed. That is why my code is full of this:
if(!connect(this,SIGNAL(colorChanged(QColor)),&ob,SLOT(onColorChanged(QColor)),(Qt::ConnectionType) (Qt::QueuedConnection | Qt::UniqueConnection) )) {
qWarning()<<"ERROR: Could not connect "<<ob.objectName();
}
Notice the last parameter to the connect call, as it specifies Qt::QueuedConnection and Qt::UniqueConnection connections. Qt::QueuedConnection means that it is "thread safe" in that it will store the signal in a thread safe FIFO. Qt::UniqueConnection just means that connecting twice will generate an error the second time instead of creating two connections (which may lead to hard-to-trace bugs).
Third, are you starting any threads without using Qt? In that case care should be taken with signals, because they might not work properly unless you are working with Qt initiated threads. I THINK the Qt::QueuedConnection trick above should be enough, but I don't know. Here is more. Oh, and if OpenCV ever decides to knowingly or unknowingly start some threads of it's own, they will count as "threads started outside Qt".
Fourth, did you run this in a debugger? At what exact point did it crash? This should be your first move, btw.
Fifth, If all else fails wrap your code in a QMutex and use QMutexLocker to ensure that there is no problems. Or you could get fancy and use some thread safe containers or some such.
PS: Please let me know how you fare!
I have a QSharedMemory to prevent that two processes of my application are running at the same time. Process A sets the QSharedMemory to "locked" when started. Now my process B sets a value like "please come back to foreground".
Is there an easy way for process A to observe changes in the QSharedMemory, i.e. avoids implementing a stupid pulling timer?
Here we are: QSystemSemaphore
Like its lighter counterpart QSemaphore, a QSystemSemaphore can be accessed from multiple threads. Unlike QSemaphore, a QSystemSemaphore can also be accessed from multiple processes.
Like QSharedMemory, QSystemSemaphore uses a key-based access method.
Instead of using shared memory, the process could open a QLocalSocket to a named local server, and when it fails, open a QLocalServer. All subsequent processes will success to open the socket to the server, and can communicate with it. That's probably the simplest, most portable way of accomplishing the job.
You can also use QtSingleApplication, iff it has been ported to Qt 5.
To answere your question: No, QSharedMemory does not have such a feature.
If you just want to have a "single instance" application, you can use https://github.com/Skycoder42/QSingleInstance.
It makes shure you have only 1 instance of you application at a time, can automatically bring the active window to the front and allows you to pass parameters from the new process to the running one.
Simple example:
#include "mainwindow.h"
#include <QApplication>
#include <QMessageBox>
#include <qsingleinstance.h>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QSingleInstance instance;
MainWindow *w = NULL;
instance.setStartupFunction([&]() -> int {
w = new MainWindow(NULL);
instance.setNotifyWindow(w);
w->show();
return 0;
});
QObject::connect(qApp, &QApplication::aboutToQuit, [&](){
delete w;
});
QObject::connect(&instance, &QSingleInstance::instanceMessage, [&](QStringList args){
QMessageBox::information(w, "Message", args.join('\n'));
});
return instance.singleExec();
}
This will show the mainwindow, just like you woudl expect. If the application is run a second time, the currently running mainwindow will be raised to the foreground and a messagebox with the arguments will be shown.
Note: This example uses the QWidgets, but the QSingleInstance can be used with a gui or core application, too.
I have made my app into a single instance app using the RunGuard code found on this SO question:
Qt: Best practice for a single instance app protection
What I'd like to do is when the user tries to start the application while there is one running is to bring the existing running application to the front, and if minimised, restore it.
In my Delphi Windows programming days I used to broadcast a Windows message from the new application before closing it. The existing app would receive this and restore itself and come to the front.
Is something like this possible with Qt on Windows and Linux platforms?
Did you have any specific trouble with QtSingleApplication? It should be sufficient for what you want and will enable you to send a message to the running application. You just need a slot to get that message and if it matches what you expect then you restore it.
http://doc.qt.digia.com/solutions/4/qtsingleapplication/qtsingleapplication-example-trivial.html
The logview object is also set as the application's activation window. Every time a message is received, the window will be raised and activated automatically.
For some reason setActivationWindow() and activateWindow() don't work for me. This is my workaround:
#include <QWidget>
#include <qtsingleapplication.h>
class Window : public QWidget
{
Q_OBJECT
public:
Window(QWidget *parent = 0) : QWidget(parent) {}
public slots:
void readMessage(const QString &str) { showNormal(); }
};
int main(int argc, char *argv[])
{
QtSingleApplication instance(argc, argv);
Window *window = new Window;
window->show();
QObject::connect(&instance, SIGNAL(messageReceived(const QString &)), window, SLOT(readMessage(const QString &)));
if (instance.sendMessage(""))
return 0;
return instance.exec();
}
#include "main.moc"
In common, it is not possible without IPC. QtSingleApplication provide such IPC, but you will get extra dependency from QtNetwork module. (As #svlasov answered)
First problem that you will have: you can't raise any window of application if this application is not foreground. There are solutions for Windows and OS X, how to force raising of windows.