DropShadow is very slow when its radius is getting changed
-
I'll begin with my testcase. It's pretty basic.
- It creates a rectangle rotating in 3D, and a DropShadow element for the rectangle.
- It animates the
radius
property of the DropShadow. - It creates a 1x1px Canvas3D repainted constantly, so I can check how often it manages to get repainted with all the other stuff going on (Canvas3D has a built-in
fps
property). I use that for measuring the app's framerate.
When the value of
radius
is animated, the app is running at 10FPS. When this value is not animated, the app is running at 60FPS.The point of the 3D rotation is to have some animation in the rectWrapper element, so the shadow has to get constantly recalculated, even if its radius is not changed. This proves that calculating the shadow is very fast, and what's slowing it down is just the constant changing of the
radius
.My code:
main.cpp: (the only unusual thing in it is
AA_UseOpenGLES
, which is necessary because of my sub par OpenGL drivers)#include <QGuiApplication> #include <QQmlApplicationEngine> int main(int argc, char *argv[]) { QGuiApplication::setAttribute(Qt::AA_UseOpenGLES); QGuiApplication app(argc, argv); QQmlApplicationEngine engine; engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); return app.exec(); }
main.qml:
import QtQuick 2.5 import QtQuick.Window 2.2 import QtGraphicalEffects 1.0 import QtCanvas3D 1.1 Window { visible: true width: 640 height: 480 Text { text: canvas3d.fps + " FPS" font.pointSize: 18 } // `rectWrapper` is needed as a layer of indirection around // `rect` so DropShadow is aware of `rect`'s the rotation Item { id: rectWrapper width: rect.width // +100 here to accomodate the extra space needed due to // 3D perspective projection of the 3D-rotated inner item height: rect.height + 100 anchors.centerIn: parent visible: false Rectangle { id: rect color: "red" width: 300 height: 100 anchors.centerIn: parent property real yRot: 50 transform: Rotation { origin.x: rect.width/2; origin.y: rect.height/2; axis { x: 0; y: 1; z: 0 } angle: rect.yRot } SequentialAnimation on yRot { loops: Animation.Infinite NumberAnimation { from: -180; to: 180; duration: 5000 } } } } DropShadow { source: rectWrapper anchors.fill: rectWrapper samples: 16 radius: 16 SequentialAnimation on radius { //running: false loops: Animation.Infinite NumberAnimation { from: 2; to: 16; duration: 1000 } } } Canvas3D { id: canvas3d width: 1; height: 1 // nonzero size so it can be redrawn property var gl; onInitializeGL: { // should get and save context, otherwise FPS isn't measured for some reason gl = canvas3d.getContext("canvas3d", {depth:true, antialias:true, alpha:true}); } } }
Uncomment the
running: false
to see the huge speedup.My theory: The blur shader used by
DropShadow
may be getting recompiled on every change of radius. I've heard of that happening when you upload new values ofbool
uniforms in GLSL, but in this case it's not abool
, it's areal
.The question: Why does this slowdown occur? Can I work around it?