Embedded Qt GUI Artifacts Appear when Dismissing Widgets - qt

I am working on a touchscreen GUI for an embedded Linux device that will sit over a video feed. Therefore, I need my GUI to be transparent and disappear after some timeout so the user can just view the video feed. The main.cpp of my GUI ensures that the background of the entire application running with the -qws option is transparent with the following code:
QApplication a(argc, argv, QApplication::GuiServer);
QWSServer::instance()->setBackground(QBrush(Qt::NoBrush));
QWSServer::setCursorVisible (false);
I have a main, bottom level widget that owns every other widget in the GUI. I set the background to transparent with the following pallete related code.
QPalette transparentPallete;
transparentPallete.setColor(QPalette::Window, Qt::transparent);
setAutoFillBackground(true);
setPalette(transparentPallete);
I also overrode the paintEvent method to try to ensure that the background would always be in a clean transparent state:
void MainWidget::paintEvent(QPaintEvent *event)
{
QPainter p(this);
// Fill background
p.setPen(Qt::NoPen); // no outlines
p.fillRect(0,0,width(),height(),QColor(255, 255, 255, 0)); // Fill rectangle with color
}
Now I can launch my application and view my GUI over the raw video feed and I can interact by touch to bring up different windows within the GUI and have them disappear.
What I cannot accomplish is to get rid of artifacts that are left behind when I hit 'cancel' or order certain portions of the GUI to disappear. These artifacts look really ugly ( multiple vertical lines / wrong colors ) and only disappear when another part of the GUI is summoned that replaces that location on the screen. They are there regardless of whether I have the video feed enabled ( which lives on a different overlay controlled by the processor dss anyway ).
How can I get rid of these artifacts that are left behind after dismissing some widgets?
NOTE: This definetly is correlated with the following line:
QWSServer::instance()->setBackground(QBrush(Qt::NoBrush)); // Allows transparent pixels to be written to frame buffer
If I turn this line off, I cannot see the underlying overlay but I also do not get any strange behavior whatsoever and my performance becomes much better. How can I achieve transparency but also lose the strange artifacts?

Well the following has an issue apparently:
QWSServer::instance()->setBackground(QBrush(Qt::NoBrush));
But this solves the problem and I see 0 artifacts:
QWSServer::setBackground(QBrush(QColor(0, 0, 0, 0)));

Related

Offscreen rendering with QQuickFramebufferObject

I'm trying to experiment with offscreen rendering with QQuickFramebufferObject. It appears that I cannot do it -- if I try to bind a FBO to render offscreen, the framebuffer ends up being permanently blue after I release the FBO and attempt to render to the framebuffer.
To make sharing code easier, I've uploaded an example to https://github.com/sohailshafii/textureinsgnode_offscreen. It is basically the "textureinsgnode" Qt example modified to include a FBO that can be rendered to. Right now in the render function of fboinsgrenderer (https://github.com/sohailshafii/textureinsgnode_offscreen/blob/master/fboinsgrenderer.cpp) I disable offscreen rendering:
// uncomment this block of code to see an incorrect rendering
/*m_fbo->bind();
logo.render();
update();
m_fbo->release();
m_fbo->bindDefault();*/
logo.render();
update();
But once I uncomment the FBO here, I get a solid blue screen. I've viewed offscreen rendering examples in QT but unfortunately they don't describe how it's done with QQuickFramebufferObject. I'm running QT 5.7.1.

Limitations of using GLFW and OpenGL for GUIs

I would like to know what kind of limitations can result from using GLFW and OpenGL instead of using a traditional GUI toolkit like Qt or GTK.
Of course, I know that GLFW with OpenGL don't expose the same level of functionality, but if only a few kind of widgets are needed, I think that those could be easily implemented.
The question is, is there some feature that couldn't be implemented on top of GLFW/OpenGL in contrast to Qt or GTK?
For example, I'm worried about drawing menus outside the window region (I guess that an auxiliary non-decorated window could be use in this case).
I know that GLFW with OpenGL don't expose the same level of functionality, but if only a few kind of widgets are needed
When it comes to OpenGL, there isn't any limit per se. You can draw wherever and whatever you want. The area where you can draw is a limiting factor from the operating system's side of things.
Remember that some "simple" functionality like say a textbox, is already complicated. Not only do you have to handle rendering (and scalable text isn't always fun), but you also have to handle keyboard events. Drawing the cursor and text selection, etc.
For example, I'm worried about drawing menus outside the window region (I guess that an auxiliary non-decorated window could be use in this case).
When it comes to drawing outside the window region, this isn't directly OpenGL related. It's more a question depending on the OS.
For instance using the WinAPI, you can draw anywhere on the screen simply by doing:
#include <Windows.h>
int main(int argc, char **argv)
{
HWND desktop = GetDesktopWindow();
HDC dc = GetDC(desktop);
RECT rect = { 20, 20, 200, 200 };
HBRUSH brush = CreateSolidBrush(RGB(0, 0, 255));
FillRect(dc, &rect, brush);
return 0;
}
Note that the rectangle will disappear immediately when the screen redraws that area.
When you already have a window, then you can use SetWindowRgn() to change the area which your application is allowed to draw within. Note that you can't just change this area, and everything will be fine and dandy.
The question is, is there some feature that couldn't be implemented on top of GLFW/OpenGL in contrast to Qt or GTK?
Bottom line is no. There's isn't any feature you can't implement with OpenGL that is in Qt and GTK. The point is that it isn't just OpenGL, and that a lot of it depends on the operating system, thus needing OS specific code.

How to draw over everything on the screen using Qt?

The basic idea is: I would like to draw over everything on the screen.
One way I can imagine this is creating a transparent full-screen window without window controls (minimise, maximise, etc.) or borders. Then drawing into that window which is transparent. The problem I can think of is that I will be unable to control windows which are behind our transparent window.
How could I do something similar to this, without the mentioned problem? I would also like it to work on multiple operating systems if possible.
Edit:
The user will not be drawing with the mouse or other means on the screen, but will be able to continue use his desktop like normal, without that my program interferes in any way (other than the drawing on the screen). My program will only display something on the screen, which the user will be unable to interact with (at least that's the plan).
Qt 5 implements it:
QWidget w;
w.setWindowFlags(Qt::WindowTransparentForInput);
Qt 4 didn't support this functionality yet - see QTBUG-13559. The bug report had a hint on what needed to be done for Windows.
The method you describe is the one to use; a transparent full-screen window.
If you're using the left mouse button to draw, you'll need a mechanism of switching modes to be able to select items through the window and send events to the operating system.

Hide cursor in fullscreen mode using Qt 4.8?

I'm in a ArchLinux with OpenBox and I want to hide the cursor on fullscreen inside a Qt 4.8 application. I am aware about some other question about it but no one works every time: sometimes the cursor is hiding, sometimes not. I didn't managed to understand exactly when the problem occurs but I think that maybe is it related with the screensaver because if I test my application just after the computer is restarted the mouse cursor is no visible (and it is what I want) but if I test this feature during the day the mouse cursor is still visible in fullscreen.
This is my code:
void MainWindow::toggleFullScreen()
{
if(!this->isFullScreen())
{
this->showFullScreen();
#ifdef Q_WS_QWS
QWSServer::setCursorVisible( false );
#endif
}
else
{
this->showNormal();
}
}
I want to hide the cursor on fullscreen ...
You could set the cursor to be the blank cursor:
widget->setCursor(Qt::BlankCursor);
Also, as the docs state:
Some underlying window implementations will reset the cursor if it leaves a widget even if the mouse is grabbed. If you want to have a cursor set for all widgets, even when outside the window, consider QApplication::setOverrideCursor().
So you can call:
QApplication::setOverrideCursor(Qt::BlankCursor);
There is a program named unclutter that hides the mouse pointer. Here's an ArchLinux package:
https://www.archlinux.org/packages/community/i686/unclutter/
I currently use it on an embedded system for hiding the mouse cursor on a touchscreen.

How can I hunt down these OpenGL calls that are distorting objects in my scene?

I'm mixing two libraries that use OpenGL: Qt and OpenSceneGraph. I'm targeting OpenGL ES 2, so everything is done with shaders and ES 2 compatible calls.
I'm specifically using OSG with QtDeclarative by trying to paint OSG onto a QDeclarativeItem. I do this the way suggested in Qt documentation: wrap all OpenGL calls between beginNativePainting()/endNativePainting().
This works fine until I use textures in my OpenSceneGraph scene. When I do this, my QML window gets "messed up" for lack of a better word. To keep it as simple as possible, my OSG scene consists of a plane with a texture applied to it. I recreated the scene using basic OpenGL calls and the problem no longer occurs. Here's the problem summarized as a bunch of pictures:
The QtDeclarative engine uses OpenGL to paint stuff. I set up a simple QML page:
I create a simple scene using OpenGL directly. It's a plane with a texture painted onto it.
Now I try to set up the same scene in OSG... identical shaders, etc.
You can see something odd is going on with the last screenshot. Don't worry about the black background where the original OpenGL scene was transparent, that's just OSG using a black clear color. The problem is that the other items set up with QML (the rectangles) get messed up.
Edit: To clarify what happens: The rectangles I draw with QML are all stretched out to the right edge of the screen. I also noticed if I draw rectangles after the OpenSceneGraph item in QML, they don't show up (I didn't notice this before). I draw the purpley black rectangle after the OSG item in the following screenshots... note that it disappears. There might be more weird stuff happening, but this is all I've observed playing with rectangles.
Before
After
I'm fairly new to OpenGL so I don't know what kind of call/state setting would cause something like this to happen. I think that OpenSceneGraph makes some OpenGL state change that's messing up Qt's paint engine. I also know that this only occurs when OSG uses textures... if I don't apply textures in my OSG scene, this doesn't happen. This is where I'm stuck.
Also, I tried to use BuGLe to get an OpenGL call trace with and without textures enabled in OSG to see if I could figure out the problematic state change(s). I found a few differences, and even some global state that OSG changed (such as glPixelStorei()) between the two, but resetting the changes I found made no difference. It would help a lot if I knew what to look for. If anyone's feeling insane, I also have the stack traces:
OSG with texturing: http://pastie.org/4223182 (osg texture stuff is lines 637~650)
OSG without texturing: http://pastie.org/4223197
Edit 2:
Here's a diff that might be helpful. You'll need to scroll way down before the relevant lines are apparent.
http://www.mergely.com/nUEePufa/
Edit 3:
Woah! Okay, that diff helped me out quite a bit. OSG enables VertexAttribArray 3 but doesn't disable it. Calling glDisableVertexAttribArray(3) after OSG renders its frame seems to partially solve the problem; there's no more stretching of the QML rectangles. However, rectangles drawn after the OSG item still don't show up.
After obsessing over the trace logs, I think I've found two OpenGL things that need to be reset before passing control back to Qt to cause the issues above to go away. I mentioned one in an edit... I'll summarize both in this answer.
Rectangle/QML Item distortion
QPainter uses Vertex Attributes 3, 4, and 5 directly for something that looks like its related to the geometry of those rectangles. This can be seen in the trace:
[INFO] trace.call: glVertexAttrib3fv(3, 0x2d94a14 -> { 0.00195312, 0, 0 })
[INFO] trace.call: glVertexAttrib3fv(4, 0x2d94a20 -> { 0, -0.00333333, 0 })
[INFO] trace.call: glVertexAttrib3fv(5, 0x2d94a2c -> { 0.2, 0.4, 1 })
Disabling the corresponding vertex attribute arrays fixes the stretchy rectangles issue:
glDisableVertexAttribArray(3);
glDisableVertexAttribArray(4);
glDisableVertexAttribArray(5);
Items drawn after the OSG Item don't render
In retrospect, this was one was easy and didn't have anything to do with texturing. I hadn't noticed this before trying to add textures to my scene though, so mixing the two issues was my fault. I also screwed up with the traces and diff I posted; I never updated them to account for the ordering problem after I discovered it (sorry!)
Anyways, QPainter expects depth testing to be turned off. Qt will turn depth testing off when you call beginNativePainting(), and also when it starts to paint its items... but you're expected to turn it back off whenever handing control back:
QPainter paints stuff (DEPTH_TEST = off)
OSG draws stuff (DEPTH_TEST = on)
QPainter paints more stuff [expects DEPTH_TEST = off]
The right trace logs showed that I wasn't doing this... So the fix is
glDisable(GL_DEPTH_TEST)
Maybe you just need to reenable GL_TEXTURE_2D? I notice in your example with textures that OSG enables, and subsequently disables GL_TEXTURE_2D. Thus the difference between your two cases (with texture vs without), is that the one that uses textures finishes with texturing disabled, while the one without texturing leaves GL_TEXTURE_2D in it's initial state.
If Qt needs/expects texturing enabled to draw quads it could cause nothing to show up.

Resources