Important: Please read the Qt Code of Conduct -

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 app(argc, argv);
        QQmlApplicationEngine engine;
        return app.exec();


    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 of bool uniforms in GLSL, but in this case it's not a bool, it's a real.

    The question: Why does this slowdown occur? Can I work around it?

Log in to reply