Javafx 2d text rendering speed up - 2d

I am a little surprised that JavaFX do consume my CPU by showing simple floating text on a screen.
My question is there any option tweaks to turn on hardware acceleration for nodes like Text? To Use GPU and not CPU when rendering 2D primitives?
Here is the simple example that consume up to 40% cpu on my 2.53Mhz core 2 duo + Nvidia 9600M GT. OS: Mac Os X. JavaFX 1.2; JRE 1.5
Edit: I put animation in the example to just simulate text scrolling. You can try and achieve the same CPU consuming by scrolling ListBox or some picture with no stopping.
package text2dacceleration;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.layout.VBox;
import javafx.scene.transform.Transform;
import javafx.scene.text.Text;
import javafx.animation.*;
def longLine = for (i in [1..45]) "{i}";
def textNodes = for (i in [1..64]) Text{content: "{longLine} line number {i}"};
var yoffset = 0.0;
Timeline {
repeatCount: Timeline.INDEFINITE
autoReverse: true
keyFrames: [
KeyFrame { time: 0s values: [yoffset => 0.0]}
KeyFrame { time: 1s values: [yoffset => 10.0]}]
}.play();
Stage {
title: "Text nodes"
width: 800
height: 600
resizable: false
scene: Scene {
content: [
VBox {
content: textNodes
transforms: bind Transform.translate(0, yoffset);
}]}}

Have you played with Timeline's framerate variable? Lowering that might help.
(The framerate description: The maximum framerate at which this animation will run, in frames per second.)
Probably won't have an impact but KeyFrame has a "canSkip" option.

Sun did a lot of work on this starting at 1.5 and through 6 but I don't know how much of it filtered through to Apple's JRE implementation. For comparison is it possible for you to update to a newer JRE such as 1.6? If you can't run the latest version of OSX and therefore can't do you have a Windows machine available on boot camp or whatever it might be worth trying one of the later Sun reference ones to see how you get on.
It might also be worth a post to the JavaFX forum - http://forums.sun.com/forum.jspa?forumID=932
Sun are usually pretty good at responding to these.

VBox {
cache: true
content: textNodes
transforms: bind Transform.translate(0, yoffset);
...
--
cache: A performance hint to the system to indicate that this Node should be cached as a bitmap.

Related

How to achieve butter smooth motion in pixi.js (without any lags / spikes)

I'm trying to achieve butter smooth motion using pixi.js. It should be a simple thing I suppose but it seems I can't obtain it.
Sometimes I get spikes / micro lags. I've tested it on my Ubuntu 20.04 dev machine using the latest Chrome version and the latest PIXI js (5.3.3 actually). Same thing happens on the latest Chrome on my old Macbook pro (late 2013)
This is the code I'm using:
const app = new PIXI.Application({
view: document.querySelector("#view"),
width: window.innerWidth,
height: window.innerHeight,
backgroundColor: 0x0,
antialias: false
})
const ticker = PIXI.Ticker.system
const box = new PIXI.Graphics()
box.lineStyle(1, 0xff0000)
.drawRect(
100,
100,
100,
100)
app.stage.addChild(box)
let speed = 4
app.ticker.add( (dt) => {
if (box.x < 0) {
speed *= -1
box.x += speed * dt
}
if (box.x > 800) {
speed *= -1
box.x += speed * dt
}
box.x += speed * dt
})
Here a running version https://codepen.io/ferama/pen/LYZVBMx
What I'm missing?
You will never be able to eliminate occasional stuttering in a WebGL animation. Underneath every web rendering framework (including PixiJS) is a call to requestRenderFrame(). Which, as its name implies, is a request to the browser to repaint the window. You will not always get back a "sure, do it right now!" from the browser. Sometimes the browser is busy. Sometimes, your javascript garbage collector has to run. Sometimes a butterfly flaps its wings in China...
Point is, the only way to completely control your framerate is to use a technology such as DirectX that allows complete control over the actual rendering and display hardware (mostly!). WebGL is simply not geared for that.
It was running just fine for me, however you can try setting antialias: true and resolution: window.devicePixelRatio.

Why does Qt renderer rebuild all batches every frame

I have about 20 batches in my app and most of them are rendered using my shaders via ShaderEffect QML node. I want to optimize my app to run smoothly on i.MX6 Solo, so I profiled it with QSG_RENDERER_DEBUG=render. And I saw a couple of strange things in the output:
Renderer::render() QSGAbstractRenderer(0x2500db17e30) "rebuild: full"
Rendering:
-> Opaque: 52 nodes in 9 batches...
-> Alpha: 26 nodes in 11 batches...
- 0x25012c17e70 [ upload] [noclip] [opaque] [ merged] Nodes: 13 Vertices: 52 Indices: 104 root: 0x0
...
- 0x25012bbecc0 [ upload] [noclip] [ alpha] [ merged] Nodes: 1 Vertices: 56 Indices: 84 root: 0x0 opacity: 1
-> times: build: 0, prepare(opaque/alpha): 0/0, sorting: 0, upload(opaque/alpha): 0/0, render: 3
Every single frame all batches are rebuilt, even though most of them never change. I found that there is one text item that triggers this full rebuild. When I disable it, stop updating it or use clip: true on it, it no longer triggers a full rebuild. This text item has a unique size, so it lives in a separate batch and should not interfere with any other batches. I don't understand such behavior. Is it a Qt renderer bug?
The second weird thing is that I have a ShaderEffect with a GridMesh resolution 1x40. I never move it. I just change a couple of its uniforms and draw something with a different shader above it. However, this mesh uploads every frame.
Why does Qt scene graph upload meshes when it could easily reuse them? How to force it not to do so? I tried clip: true but it doesn't help with the second issue. I think that defining geometry in C++ can help. I haven't written any Qt render code in C++ so far, so I'm looking for ways to do it entirely in QML.

QtWayland client distorted on Raspberry Pi 4

I'm trying to create a very simple wayland compositor using the examples found here, like this:
import QtQuick 2.12
import QtQuick.Window 2.2
import QtWayland.Compositor 1.3
WaylandCompositor {
id: wlcompositor
WaylandOutput {
compositor: wlcompositor
window: Window {
width: 800
height: 480
visible: true
title: wlcompositor.socketName
Grid {
anchors.fill: parent
anchors.margins: 100
columns: 2
Repeater {
model: shellSurfaces
ShellSurfaceItem {
id: shellSurfaceItem
autoCreatePopupItems: true
shellSurface: modelData
onSurfaceDestroyed: shellSurfaces.remove(index)
}
}
}
}
}
ListModel { id: shellSurfaces }
XdgShell {
onToplevelCreated: shellSurfaces.append({shellSurface: xdgSurface})
}
}
And then I'm creating a separate client app that just creates a couple Rectangles as a test.
import QtQuick 2.12
import QtQuick.Window 2.12
Window
{
id: window
visible: true
width: 200
height: 200
Rectangle
{
anchors.fill: parent
color: "green"
Rectangle
{
x: 10
y: 10
width: 100
height: 100
color: "blue"
}
}
}
Everything seems simple and straightforward. But when I run it on my Pi4 (using the -platform wayland flags), the client gets crazy distortion, like this:
I'm testing it with Boot2Qt, which is a yocto linux image. I've tried Qt versions 5.14.2 and the newest 5.15.0 with the same results. There are no errors on the console. Nothing that indicates anything is wrong except that it looks awful.
I did notice that if I use weston as my compositor instead of QtWayland, then the app looks perfect. So that makes me think there's something wrong with WaylandCompositor. But my search of google found nobody else complaining of the same thing.
I don't even know what to try. Does anybody have any ideas?
I had similar effects using qt 5.15.1 and qt 5.15.2 with qt wayland on the pi 4. I managed to get QT Wayland working with no distortion by compiling the mesa driver 20.3.3 and 20.3.4, using the following options:
-Dplatforms=x11,wayland -Dvulkan-drivers=broadcom -Ddri-drivers= -Dgallium-drivers=kmsro,v3d,vc4 -Dbuildtype=release -Dprefix=/usr -Degl=true
After installing the drivers i updated the sysroot on my host and cross-compiled the QT Lib.
That made it finally working. Good luck.
I've encountered this very same issue from Qt 5.12 to 5.15, and Qt 6.2.0 RC.
The solution to avoid distortion is to enable dma-buf in QtWayland, and set hardware integration from the compositor side:
export QT_WAYLAND_CLIENT_BUFFER_INTEGRATION=linux-dmabuf-unstable-v1
export QT_WAYLAND_SERVER_BUFFER_INTEGRATION=dmabuf-server
Note that in order to enable dma-buf it required me to tweak .pro and configure.json files (I'm doing native build on the Pi4), as the libdrm-dev header couldn't be detected by qmake or cmake correctly.
Add INCLUDEPATH += /usr/include/libdrm/ to the following two:
./src/plugins/hardwareintegration/client/dmabuf-server/dmabuf-server.pro
./src/plugins/hardwareintegration/compositor/dmabuf-server/dmabuf-server.pro
And add libdrm/ before drm headers in following files:
./src/client/configure.json
./src/compositor/configure.json
A re-configure & rebuild should work. Tested on Pi4 + Qt 5.15.2 with both armhf and arm64 image, using dtoverlay=vc4-kms-v3d-pi4 overlay.
If memory serves me correctly, the closed-source graphics driver are a real pain when it comes to wayland support. You may have some luck by enabling the broadcom backend (which I think it's what appropriate for rpis) for qt wayland by setting QT_WAYLAND_CLIENT_BUFFER_INTEGRATION=brcm before starting the compositor.
There is some info about this env var in this readme: https://code.qt.io/cgit/qt/qtwayland.git/tree/README
But if practically possible, I would think the mesa open-source drivers will give you a lot less pain, as it's much more widely used and support is likely much better.

Qt QML Settings are not saved/applied

I have simply copied this example from the docs, adjusting the import version number to the newest ones (but I tried with both for same result).
import QtQuick.Window 2.12
import Qt.labs.settings 1.1
Window {
id: window
width: 800
height: 600
Settings {
property alias x: window.x
property alias y: window.y
property alias width: window.width
property alias height: window.height
}
}
As opposed to advertised, the window geometry was not saved after I closed and reopened the window. In fact, it now doesn't show the window at all? (I tried re-running qmake and cleaning all)
I also get this warning every time I run the project in Qt Creator, regardless of whether I use Settings or not:
17:01:02: Starting C:...debug\untitled.exe...
QML debugging is enabled. Only use this in a safe environment.
qrc:/main.qml:10:5: QML Settings: Failed to initialize QSettings instance. Status code is: 1
qrc:/main.qml:10:5: QML Settings: The following application identifiers have not been set: QVector("organizationName", "organizationDomain")
1) Is the warning related to the issue?
2) How do I remove the warning?
3) How do I get the settings to be applied as advertised?
...Turns out I had to keep reading the docs to the end.
1) Warning is related to the issue.
2) Per the docs, add this at the beginning of the main in main.cpp
app.setOrganizationName("Some Company");
app.setOrganizationDomain("somecompany.com");
app.setApplicationName("Amazing Application");
3) Now works as advertised.

What is qmltestrunner?

I have gone through the documentation provided by Qt on TestCase, Qt Quick Test Reference Documentation, Ubuntu QML unit testing, Testing with qmltestrunner part 1 & 2, Writing and running qml testcases, How to create a Qt-Quick Test
All that I have found about it is:
Qmltestrunner is a tool used for unit testing. This tool allows to execute QML files as test cases. These files should contain test_functions. Qmltestrunner is an open-source project and its source code can be found from the github.
But there are few questions for which I'm looking out for answers:
qmltestrunner documentation? where can I find it? (Could not find wiki page for it)
Is qmltestrunner part of qt quick test framework?
What all dependencies are there for qmltestrunner?
Is there any proper example where I can find complete explanation about QML unit testing? qt quick test framework explains running-tests which I couldn't understand.
Thank you
Unfortunately there's no documentation for qmltestrunner (I cannot one). If you only want to know how to use it, qmltestrunner.exe -h may help you. Most options are described in Qt Test Overview.
Yes. Qt Quick Test Reference Documentation - Running Tests says you need a .cpp file that contains QUICK_TEST_MAIN(xxx) and a .pro file that contains CONFIG += qmltestcase, and build this project to run your QML unit tests. The output binary file of this project is (almost the same as) qmltestrunner.
To run qmltestrunner (in Windows with Qt 5.7, for example), you need at least the following modules: Qt5Core.dll, Qt5Gui.dll, Qt5Network.dll, Qt5Qml.dll, Qt5Quick.dll, Qt5QuickTest.dll, Qt5Test.dll, Qt5Widget.dll. And some extra modules for your QML files if needed (ex. QtQuick Controls 2)
TestCase describes how to write a unit tests in QML. To run the file, simply run qmltestrunner.exe -input C:\My\Testing\File\Path\tst_myComponentTest.qml in command line.
Here's simple step-by-step example about how to write a QML component with unit tests. For example, assume that we have a ExpandButton that expands when it is clicked:
//ExpandButton.qml
import QtQuick 2.7
import QtQuick.Controls 1.2
Button {
width: 50; height: 50
onClicked: { width = 100; }
}
To test this behavior, write a tst_ExpandButton.qml:
import QtQuick 2.7
import QtTest 1.0
Item {
width: 800; height: 600
ExpandButton {
id: expandButton
anchors.centerIn: parent
}
TestCase {
name: "ExpandButton"; when: windowShown
function test_clickToExpand() {
var widthBeforeClick = expandButton.width;
mouseClick(expandButton);
var widthAfterClick = expandButton.width;
verify(widthBeforeClick < widthAfterClick);
}
}
}
Now we have two QML files, ExpandButton.qml and tst_ExpandButton.qml. Run the unit test with qmltestrunner.exe -input D:\aaa\bbb\tst_ExpandButton.qml and you can see the result:
********* Start testing of qmltestrunner *********
Config: Using QtTest library 5.7.0, Qt 5.7.0 (i386-little_endian-ilp32 shared (dynamic) release build; by MSVC 2015)
PASS : qmltestrunner::ExpandButton::initTestCase()
PASS : qmltestrunner::ExpandButton::test_clickToExpand()
PASS : qmltestrunner::ExpandButton::cleanupTestCase()
Totals: 3 passed, 0 failed, 0 skipped, 0 blacklisted, 13ms
********* Finished testing of qmltestrunner *********
http://doc.qt.io/qt-5/qtquick-qtquicktest.html This will help in understanding qmltest runner
http://doc.qt.io/qt-5/qml-qttest-signalspy.html This will help in understanding signal spy which is used to catch signals
http://doc.qt.io/qt-5/qml-qttest-testcase.html This will help in writing each test case

Resources