Qt: QOpenGLContexts "mix" with differnt widgets - qt

I am recently building a Qt application with native openGL streaming data in the Qt window.
I have 2 widgets inherited from QOpenGLWidget, one has parent, the other doesn't have a parent. They both work well individually (just show() one widget per time). However, when I try to render them simultaneously, one of the texture I bind via glBindTexture() appears in the wrong window. It's like they are using the same context(). But by inheriting from QOpenGLWidget, they should have two different context.
In my code, I just override initializeGL, paintGL and resizeGL as usual
void initializeGL(){
initializeOpenGLFunctions();
// generate buffer, allocation, shaders...
}
void paintGL(){
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
// bind vao, bind texture, drawElements...
}
Basically, my second window(window2) is a "video player" plays the image sequence from memory. But it appears on the window1. I have also set a QSurfaceFormat by:
QSurfaceFormat format;
format.setRenderableType(QSurfaceFormat::OpenGL);
format.setVersion(3,3);
format.setProfile(QSurfaceFormat::CoreProfile);
setFormat(format);
in the constructor.
Could someone tell me what might be wrong here? I think the context() the two windows use are different, then how could I glBindTexture in window2 could apply for window1? If you found these information are not enough, please tell me, Thanks.
platform: Ubuntu16.04, Qt5.6.2, OpenGL3.3
Update:
I have the same issue with this post: OpenGL multiple window rendering. However, mine is inside Qt5 environment, theoretically, it should works.

Related

OpenGL / QT : Need help in Converting from QImage to Opengl format and render the pixels

We are migrating from Old OpenGl to Modern OpenGL. I am trying to port two functions which uses QT/OpenGL and want to convert to Modern OpenGL. QImage content should be converted to OpenGL Format. Then I want to read the pixels of QImage and render in OpenGL. How to do this in Modern OpenGL. I know glcopypixels() / glDrawPixels() is deprecated. Any pointers? I have the following code but it is in old OpenGL. Basically the whole idea is writing to back buffer and restoring the back buffer and render pixels to avoid redraw. I am using QOpenglWidget Class given by QT Framework (QT 5.1). I have tried many things converting to OpenGL format from QImage. But it did not work. Need your help. Thanks in Advance.
QImage _savedBackBuffer;
void SaveBackBuffer()
{
glReadBuffer(GL_BACK);
QImage buf = this->grabFramebuffer();
_savedBackBuffer = convertToGLFormat(buf); // convertToGLFormat is not available in
QOpenGLWidget class
}
void restoreBackBuffer()
{
glDrawBuffer(GL_BACK);
**glDrawPixels**( _savedBackBuffer.width(), _savedBackBuffer.height(),
GL_RGBA, GL_UNSIGNED_BYTE, _savedBackBuffer.bits() ); ---> glDrawPixels is Deprecated. How to handle this call.
}
flush () {
glReadBuffer (GL_BACK);
glDrawBuffer(GL_FRONT);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
**glCopyPixels**(0, 0, _scrWidth, _scrHeight, GL_COLOR); // glCopyPixels Deprecated
...
glflush();
}
I have added below code to grab the Framebuffer. But still I am getting an Empty QImage. Anything wrong with my code.
saveBackBuffer()
{
_bSavingBackBuffer = true;
QString fileName("C:\\Users\\ey617e\\Desktop\\yourFile.png");
QFile file(fileName);
file.open(QIODevice::WriteOnly);
glReadBuffer(GL_BACK);
makeCurrent();
QOpenGLFramebufferObjectFormat format;
format.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil);
QOpenGLFramebufferObject * fbo = new
QOpenGLFramebufferObject(_scrWidth, _scrHeight, format);
fbo->bind();
paintGL();
_savedBackBuffer = fbo->toImage();
_savedBackBuffer.save(file.fileName(), "PNG");
fbo->release();
}
paintGL()
{
QOpenGLPaintDevice fboPaintDev(_scrWidth, _scrHeight);
QPainter painter(&fboPaintDev);
painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing);
painter.beginNativePainting();
drawDisplayLists(_underIllusDisplayLists);
drawDisplayLists(_illusDisplayLists);
painter.endNativePainting();
painter.drawText(20, 40, "Foo");
painter.end();
}
You can create a QOpenGLTexture object directly from a QImage: https://doc.qt.io/qt-5/qopengltexture.html#QOpenGLTexture-1
You can then use that texture directly for any image related OpenGL operations.
Basically the whole idea is writing to back buffer and restoring the back buffer and render pixels to avoid redraw.
Don't do that! It will actually impair performance, since drawing on top of previously rendered content introduces implicit synchronization points, thereby eliminating options to render new contents in parallel to advancing the presentation swap chain.
As "counterintuitive" as it may sound, just redraw the whole thing, each and every frame. If your codebase is that old, then the complexity of what you're drawing very likely is going to be so low, that you could easily render thousands of frames per second.
On the other hand retaining the contents of the backbuffer constitutes a cache and thus introduces the complexity of deciding upon cache invalidation.
I bet, that just redrawing using modern methods (geometry in buffer objects, index buffers, untangling of sync points) and simplifying the rendering code path by mere elimination the code that's responsible for determining when to actually redraw portions of the picture will actually vastly outperform anything what you had before.

Using QPainter with QPaintDevice multiple times

we all know this Warning from
bool QPainter::​begin(QPaintDevice * device)
Warning: A paint device can only be painted by one painter at a time.
http://doc.qt.io/qt-5/qpainter.html#begin
But what if I have two object sharing one pixmap, and one object Bar contains other object Foo.
class Foo
{
public:
QPixmap* barPixmap;
void draw()
{
QPainter painter(barPixmap);
painter.drawText(0,0,"FooText");
}
}
class Bar
{
public:
QPixmap* barPixmap;
Foo* fooObject;
}
and I got something like this
Bar::paintEvent(QPaintEvent* )
{
QPainter painter(barPixmap);
painter.drawText(50,50,"BarText");
fooObject->draw();
}
Is it multiple drawing? Compiler throws nothing and code seems working.
The warning tells you about creating multiple QPainters at one time. Since all paint events are processed in the main thread, they are processed consequently. As long as QPainter object is destroyed at the end of your event handler, the warning will not appear. Multiple consequent paintings on one device is fine.
However the architecture is questionable. For instance, if multiple widgets are painted this way, one of widgets will display old version of pixmap while second widget will display updated version. This inconsistency can be a problem. Putting any logic in paint event handlers is generaly pointless (and sometimes harmful). You should change pixmap when available data changes and just paint it in the paint event.

QGLWidget and hardware acceleration?

Greetings all,
Does simply subclassing QGLWidget and reimplementing paintEvent() make use of OpenGL and hardware acceleration?
I create a QPainter and draw QImages in this paintEvent().
What happen inside the paintEvent() method of QGLWidget? Does it convert the images(QImage,QPixmap) into OpenGL textures?
Does it use hardware acceleration for image scaling?
Thanks in advance,
umanga
Take a look at http://doc.qt.io/archives/4.6/opengl-2dpainting.html for an instructive example, where you can also find the following quote: "it is possible to re-implement its [QGLWidget] paintEvent() and use QPainter to draw on the device, just as you would with a QWidget. The only difference is that the painting operations will be accelerated in hardware if it is supported by your system's OpenGL drivers."
So, the answer to your first question is yes.
For figuring out the exact details of the implementation, let's take a quick peek at a piece of source-code from QOpenGLPaintEngine (which can be found by searching the internet) :
void QOpenGLPaintEngine::drawImage(const QRectF &r, const QImage &image,
const QRectF &sr, Qt::ImageConversionFlags)
{
Q_D(QOpenGLPaintEngine);
if (d->composition_mode > QPainter::CompositionMode_Plus
|| d->high_quality_antialiasing && !d->isFastRect(r))
d->drawImageAsPath(r, image, sr);
else {
GLenum target = (QGLExtensions::glExtensions
& QGLExtensions::TextureRectangle)
? GL_TEXTURE_RECTANGLE_NV
: GL_TEXTURE_2D;
if (r.size() != image.size())
target = GL_TEXTURE_2D;
d->flushDrawQueue();
d->drawable.bindTexture(image, target);
drawTextureRect(image.width(), image.height(), r, sr, target);
}
}
This answers your question regarding QImages, they are indeed drawn using textures.
Yes, if you use GL commands inside a QGLWidget, inside the paintGL, resizeGL and initializeGL methods, you will get full hardware acceleration (if available).
Also seems that using QPainter in a QGLWidget also gets HW acceleration, since there's a OpenGL QPainEngine implementation, you can read about that here.

Segmentation fault in Qt application framework

this generates a segmentation fault becuase of "QColor colorMap[9]";. If I remove colorMap the segmentation fault goes away. If I put it back. It comes back. If I do a clean all then build all, it goes away. If I increase its arraysize it comes back. On the other hand if I reduce it it doesnt come back. I tired adding this array to another project and
What could be happening. I am really curious to know. I have removed everything else in that class. This widget subclassed is used to promote a widget in a QMainWindow.
class LevelIndicator : public QWidget
{
public:
LevelIndicator(QWidget * parent);
void paintEvent(QPaintEvent * event );
float percent;
QColor colorMap[9];
int NUM_GRADS;
};
the error happens inside ui_mainwindow.h at one of these lines:
hpaFwdPwrLvl->setObjectName(QString::fromUtf8("hpaFwdPwrLvl"));
verticalLayout->addWidget(hpaFwdPwrLvl);
I know i am not providing much but I will give alink to the app. Im trying to see if anyone has a quick answer for this.
If I do a clean all then build all, it goes away.
This makes it sound as though your build system isn't recognizing a dependency and that a change to that class definition isn't triggering a rebuild of something that should be recompiled when the definition changes.
Make sure class LevelIndicator is defined in exactly one place (generally that would be a header file that gets included by whatever modules need to use a LevelIndicator object). Also make sure that any global/static instances of LevelIndicator objects are following the one definition rule.
Firstly it might not be QColor, that may simply be changing the memory layout enough that a buffer overrun somewhere else triggers a segfault - try a different size QColor ..[1] for example.
Can QColor be used as an array like this, does it have the correct default ctor?

How to set QWidget cursor outside the GUI thread

I am working on QT GUI project. In this application I have a QWidget as main window. I make the cursor from data coming from some source. When I set the cursor of widget. It gives me the following error.
QPixmap: It is not safe to use pixmaps outside the GUI thread
My code is as follows
void ImageWindow::setMouseCursor(unsigned char* data,unsigned char* maskbits,unsigned int length,int xHotSpot, int yHotSpot)
{
QBitmap bitmapData;
QBitmap bitmapMaskData;
bitmapData.loadFromData(data,length);
bitmapMaskData.loadFromData(maskbits,length);
this->setCursor(QCursor(bitmapData,bitmapMaskData,xHotSpot,yHotSpot));
this->update();
}
Function setMouseCursor is called from other class, which set the data of cursor.
ImageWindow is my customized QWidget class.
Apparently, the object which calls setMouseCursor lives outside the GUI thread as far as i can tell. In order to avoid this, make setMouseCursor a slot. Do not call the slot directly, instead emit a signal from the caller object, and connect that signal to setMouseCursor slot using Qt::QueuedConnection.
See : ConnectionType
Two problems:
don't use a QBitmap outside the GUI-thread
don't call gui objects setCursor outside the GUI-thread
Creating a Paint Device
One advantage of using QImage as a
paint device is that it is possible to
guarantee the pixel exactness of any
drawing operation in a
platform-independent way. Another
benefit is that the painting can be
performed in another thread than the
current GUI thread.

Resources