Offscreen rendering with QQuickFramebufferObject - qt

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.

Related

Pixelated gif in QT

I'm trying to show a gif file in QT app, using the approach provided in the link: https://code.qt.io/cgit/qt/qtbase.git/tree/examples/widgets/widgets/movie?h=5.15
Approach makes use of QMovie object set in a QLabel.
The example works well and fine.
But if I enable High DPI scaling for the app, the gif becomes all pixelated. Please see the screenshots below.
This is the line that I add to enable High DPI scaling.
QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
Any ideas to get this fixed ?
I have tried the following fixes already:
setScaledSize for the QMovie object
setScaledContents(true) for the QLabel
QT version I'm using is 5.15.2 and platform is Windows.
A GIF picture cannot have more than 256 unique colours. When you load such an image into Qt, it is internally represented in that exact format with the palette (of 256 colours) from the GIF representation, even if your hardware might be able to display many more colours.
This also means that when you scale such an image, Qt is not allowed to extend the colour space to render in-between colours - This means that scaled GIF pictures generally have to look much worse than scaled high-colour images.
The solution to this is either to transform the QImage you created from a GIF picture into a format with a larger colour space before scaling it (with QImage::convertToFormat) or, better still, don't use GIF images at all. After all, GIF is a format developed 30 years ago and has never really been updated to adapt to modern hardware, and using it, you artificially limit your programs to the capabilities of that format.
It seems at this moment there is no way to render sharp gifs when scaled using QMovie and QLabel. I have filed a bug for the same in QT bug tracker.
Meanwhile I have found a workaround that works fine. It is done making use of QML in the QWidget system, using QQuickWidget.
Let me add the full steps here, so that it is helpful to anyone else who run into this problem:
First we need to add support for Qml and QuickWidgets. I use CMake and Visual Studio. Hence I add the below lines in the CMakeLists.txt file. Equivalent changes needs to be made in the .pro file, if QT Creator is used instead.
# I'm only adding the relevant lines for brevity
find_package(Qt5 COMPONENTS Qml QuickWidgets)
target_link_libraries(${APP_TARGET_NAME}
Qt5::Qml
Qt5::QuickWidgets)
# Note the --qmldir switch
add_custom_command (TARGET ${APP_TARGET_NAME} POST_BUILD
COMMAND ${QTDIR}/bin/windeployqt
--qmldir ${CMAKE_CURRENT_SOURCE_DIR}/qml
${CMAKE_CURRENT_BINARY_DIR}/$<CONFIG>/${APP_TARGET_NAME}.exe)
Then create a spinner.qml file inside a folder named qml:
import QtQuick 2.15
Rectangle {
width: 12
height: 12
AnimatedImage {
y: 5
width: 12
height: 12
id: spinner
source: "img/spinner.gif"
speed: 1.0
}
}
And then load the qml file using QQuickWidget and add the QQuickWidget instance to the QWidget layout.
QHBoxLayout *main_layout = new QHBoxLayout();
auto *spinner_gif = new QQuickWidget(QUrl::fromLocalFile(":/spinner.qml"));
main_layout->addWidget(spinner_gif);
this->setLayout(main_layout);
The gif that shows up won't be pixelated even when scaled and we can see the GPU in use, in the Task Manager, as expected for a QQuickWidget.

Embedded Qt GUI Artifacts Appear when Dismissing Widgets

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)));

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.

QML flickering with Animations on images

I'm writing a QML application that displays a collection images.
To display next and previous image I use a ParallelAnimation to animate the x coordinate translation but the result is ugly: images animate but there is a flicking during the animation.
I've tried with opengl viewport and some optimizations (see here) but no success.
try adding view->setAttribute(Qt::WA_NoSystemBackground);
in main.cpp

QGraphics paints custom widget differently in paintEvent than resizeEvent and vice-versa

I have written code for my graph and it works fine, but when I need to resize it, problems start.
Resize event doesn't fit my QGraphicScene to QGraphicsView, but same code in paint event works fine.
I can't use paint event, 'cause it makes recursive painting in symbian(It works fine in desktop).
Resize event works fine if I resize window after first run, but I wan't to fit scene in my view from first run to end of program.
Here is pics of resizeEvent:
and paintEvent:
Both event's have same code inside.
Thanks in advance.

Resources