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.
Related
You can set a QTreeWidget to animated with:
tree_widget = QtWidgets.QTreeWidget()
tree_widget.setAnimated(True)
This will make the QTreeWidgetItems animate while they collapse and expand.
Is there a way to access and edit the animation speed, and type, in the same way you would a QtCore.QVariantAnimation()?
I would like to be able to change the speed and animation type (eg, QtCore.QEasingCurve.Linear) if possible.
Let's track the source;
When we look for animated property we can find out it is actually part of QTreeView class.
So first we need to check if they provided a public method (may named set/addAnimation) to access/manipulate this property. But there aren't any. (not totally true, see the update section)
Then we've to look into the source code of QTreeView. The property set at line 910 as animationsEnabled flag.
When we look for where the action taken according to this flag is at line 3096 and line 3113
And unfortunately these methods are part of QTreeViewPrivate class which is not part of Qt API according to the doc-string:
W A R N I N G
This file is not part of the Qt API. It exists purely as an
implementation detail. This header file may change from version to
version without notice, or even be removed.
We mean it.
So, I don't see a direct way to access or change it without touching and building source.
UPDATE
I recently came across to a widget-animation-duration property in Qt Style Sheet Reference to override built-in animation duration values with style sheets and decided to append it here. However, which widgets are supported is poorly documented. Fortunately, I was able to find related commit with help of google hacking:
"widget-animation-duration" inurl:"code.qt.io"
Diffstat
-rw-r--r-- src/widgets/doc/snippets/code/doc_src_stylesheet.qdoc 4
-rw-r--r-- src/widgets/doc/src/widgets-and-layouts/stylesheet.qdoc 16
-rw-r--r-- src/widgets/itemviews/qcolumnview.cpp 6
-rw-r--r-- src/widgets/itemviews/qtreeview.cpp 2
-rw-r--r-- src/widgets/styles/qcommonstyle.cpp 5
-rw-r--r-- src/widgets/styles/qstyle.cpp 9
-rw-r--r-- src/widgets/styles/qstyle.h 1
-rw-r--r-- src/widgets/styles/qstylesheetstyle.cpp 4
-rw-r--r-- src/widgets/widgets/qtabbar_p.h 2
-rw-r--r-- src/widgets/widgets/qwidgetanimator.cpp 4
10 files changed, 41 insertions, 12 deletions
QColumnView and QWidgetAnimator classes has these lines and I was able to change duration of QColumnView animations when I tested.
if (const int animationDuration = style()->styleHint(QStyle::SH_Widget_Animation_Duration, 0, this)) {
d->currentAnimation.setDuration(animationDuration);
BUT: QTreeView implementation only checks the flags existence but not using it's value yet because they animate it by rendering tree to pixmap and drawing it by pixels. We can assume they'll use it because this looks like a preparation for it:
animationsEnabled = q->style()->styleHint(QStyle::SH_Widget_Animation_Duration, 0, q) > 0;
As it is written here
https://documentation.magnolia-cms.com/display/DOCS56/Dialog+definition I assume there is a possibility for every dialog to insert the following line into the yaml:
modalityLevel: non-modal
If I do this to an existing Component-Dialog which could be quite complex (with tabs and so on) the console logs an error.
WARN agnolia.config.source.yaml.YamlConfigurationSource: 1 major and 0 minor problems have been encountered
(Note: if I do modalityLevel: light it works..)
The reason I want to do this is to have more than one dialog opened at once.
Is that possible in Magnolia 5.5.5 (or 5.6)?
Okay there we go, after some investigation it turns out that the problem is within Magnolia. I have created the following issue https://jira.magnolia-cms.com/browse/MGNLUI-4328 for the problem. For now please ignore what the definition app says and we will fix it as soon as possible.
Cheers,
FWIW, I get the same behavior on the current demo ...
It's defined here:
info.magnolia.ui.api.overlay.OverlayLayer
65 /**
66 * The available levels of modality.
67 * Determines how "modal" it is -
68 * -STRONG creates a dark background that prevents clicks.
69 * -LIGHT adds a border, creates a transparent background that prevents clicks.
70 * -NON_MODAL does not prevent clicks.
71 */
72 public static enum ModalityLevel {
73 STRONG("strong", "modality-strong"),
74 LIGHT("light", "modality-light center-vertical"),
75 NON_MODAL("non-modal", "modality-non-modal");
And it's used here:
info.magnolia.ui.framework.overlay.OverlayPresenter
216 final OverlayCloser closer = openOverlay(new ViewAdapter(shortcutPanel), ModalityLevel.NON_MODAL);
And it's used here:
info.magnolia.dam.app.assets.field.UploadAssetActionRenderer
155 progressIndicatorCloseHandle = layer.openOverlay(new ViewAdapter(progressIndicator), ModalityLevel.NON_MODAL);
and etc.
So that seems like a false positive.
Interestingly, I don't see any tests for this ... for example, I see:
assertEquals("light", session.getProperty("/modules/ui-framework/dialogs/rename/modalityLevel").getString());
and
assertEquals("strong", session.getProperty("/modules/pages/dialogs/createPage/modalityLevel").getString());
but nothing with "non-modal"
I thought maybe the "-" character, but this appears, all else equal, to be valid yaml
---
modalityLevels: strong
modalityLeveln: non-modal
modalityLevell: light
Would have to dig deeper to see what is happening here.
UPDATE: if you change it to "non_modal", there's no longer an error in the definitions app.
I want to unittest drag and drop for our widgets. At the moment, I instantiate a QDragEnterEvent, but this is discouraged with a big warning on the Qt documentation, because it relies on the Qt library internal state. In fact, I get segfaults that appear to be due to a violation of this Warning.
Given this premise, how can one test drag and drop behavior?
If using Unix we can use QTest, however to get a cross-platform solution, we can implement a solution where we circumvent Qt.
Using QTest
Although the Qt documentation for drag and drop says that it will not block the main event loop, a closer look at QDrag.exec will reveal that this is not true for Windows.
The call to QTest.mousePress causes the test to block until the mouse is physically moved by the user.
I got around this in Linux by using a timer to schedule the mouse move and release:
def testDragAndDrop(self):
QtCore.QTimer.singleShot(100, self.dropIt)
QtTest.QTest.mousePress(dragFromWidget, QtCore.Qt.LeftButton)
# check for desired behaviour after drop
assert something
def dropIt(self):
QtTest.QTest.mouseMove(dropToWidget)
QtTest.QTest.mouseRelease(dropToWidget, QtCore.Qt.LeftButton, delay=15)
For this solution, it is necessary to include a delay in the mouseRelease call, and to have called show on your widget.
Note that I have verified this works using pyqt4 and Python 2.7 on Fedora 20
Cross-Platform
You can use the mouse manipulation methods from the PyUserInput package. Put the mouse interaction in separate thread to avoid the locking up of the Qt main event loop. We can do this since we are not using Qt at all in our mouse control. Make sure that you have called show on the widgets you are dragging to/from.
from __future__ import division
import sys, time, threading
import numpy as np
from PyQt4 import QtGui, QtCore, QtTest
from pymouse import PyMouse
...
def mouseDrag(source, dest, rate=1000):
"""Simulate a mouse visible mouse drag from source to dest, rate is pixels/second"""
mouse = PyMouse()
mouse.press(*source)
# smooth move from source to dest
npoints = int(np.sqrt((dest[0]-source[0])**2 + (dest[1]-source[1])**2 ) / (rate/1000))
for i in range(npoints):
x = int(source[0] + ((dest[0]-source[0])/npoints)*i)
y = int(source[1] + ((dest[1]-source[1])/npoints)*i)
mouse.move(x,y)
time.sleep(0.001)
mouse.release(*dest)
def center(widget):
midpoint = QtCore.QPoint(widget.width()/2, widget.height()/2)
return widget.mapToGlobal(midpoint)
def testDragAndDrop(self):
# grab the center of the widgets
fromPos = center(dragFromWidget)
toPos = center(dropToWidget)
dragThread = threading.Thread(target=mouseDrag, args=((fromPos.x(),fromPos.y()), (toPos.x(), toPos.y())))
dragThread.start()
# cannot join, use non-blocking wait
while dragThread.is_alive():
QtTest.QTest.qWait(1000)
# check that the drop had the desired effect
assert dropToWidget.hasItemCount() > 0
Note I have tested this using PyQt4 and Python 2.7 on Fedora and Windows 7
Haven't tried, but if your drag & drop process is Qt internal (meaning, you're dragging from and to a Qt widget), QTest might help.
Basically by doing something along the lines:
QTest.mousePress(drag_widget, Qt.LeftButton) # simulate mouse press on whatever you want to drag
QTest.mouseMove(drop_widget) # move the mouse to the target - maybe this can be skipped
QTest.mouseRelease(drop_widget, Qt.LeftButton) # simulate mouse release where you want to drop
All functions may be supplied with further positional information (e.g. to click a list item within a widget) and with optional delays to emulate a human user.
Not a copy-pasteable answer, but maybe it serves as a starter...
i'm using JSNetworkX for graph exploration and rendering.
JSNetworkX is using D3.js for graph render. However, as I work with large graph (json file about 5Mb), I would like to render this graph directly without any animations (so, in placing each node directly without force attraction).
I try to use D3.layout.force().stop() after rendering, but it's without effects.
Because of that, I'm thinking that it has to be done in jsnx.draw, see my code below.
jsnx.draw(G, {
element: 'body',
d3: d3,
layout_attr: {
charge: -1500,
linkDistance: 1,
gravity: 1,
friction: 0.4,
alpha: -100
},
});
force = d3.layout.force();
Unfortunately, you can't do that with the current version. Do you need a force layout at all or do you already have positions for each node? FWIW, if you really have a large graph, even a static layout would be slow, because you'd still have too many SVG elements. The next version will include a WebGL rendered for large graphs.
So, we can't for the moment.
As of v0.3.4, jsnx.draw returns the force layout object so you can do var force = jsnx.draw{/*...*/} then force.stop().
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.