Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Better than QML Canvas? How to draw multiple items without sucking up CPU



  • I am drawing multiple overlapping polygons and labels on a video. The polygons and labels are all saved in a QVariantList, and I draw based upon that list. I currently draw all polygons and labels using a QML Canvas element. If there is a change to any polygon/label, I clear the canvas and redraw everything.
    I wanted to make it use even less CPU so I used ONE Canvas element per polygon. That way, if a polygon changed colors, I would only need to redraw that changed polygon without redrawing the other polygons. My theory was wrong. This solution uses even more CPU!

    In my research, it looks like I might want to use QML Scene Graph. What do you guys think?
    Here is my current qml code.

    import QtQuick 2.0
    import DrawZones 1.0
    
    
    Item {
        property real lineWidth: 3 
        anchors.fill: parent
    
        Zones {
            id: zoneOB 
            anchors.fill: parent
            objectName: "zone"
    
            property string zoneColor: "black"
    
            onZoneListChanged: {
                /*canvas.requestPaint();*/
    	    canvas0.requestPaint();
    	    canvas1.requestPaint();
    	    canvas2.requestPaint();
    	    canvas3.requestPaint();
    	    canvas4.requestPaint();
    	    canvas5.requestPaint();
                var zonelist = getZoneList;
                /*  debug only
                console.log("zonelist size: ", zonelist.length, "; zone size: ", zonelist[0].length);
                for (var i in zonelist) {
                    for (var j in zonelist[i]) {
                        if (j < zonelist[0].length-1)
                            console.log("P", i, "j=", j, ":", zonelist[i][j].x, ",", zonelist[i][j].y)
                        else
                            console.log("Color", i, "j=", j, ":", zonelist[i][j])
                    }
                }*/
            }
        } //Zone
    
        FontLoader{id: localFont; source: "Cabin-SemiBold.ttf" }
    
        Image {        
    	objectName: "test"
            visible: false
            id: tea
            anchors.top: parent.top
            width: 60
            height: 60
            source: "pics/RadarCarLarge1.png"
        }
    
        function drawZone(cntxt, zn, color, w) {
            for (var zcol in zn){
                if (zcol == 0) {
                    cntxt.beginPath();
                    cntxt.lineWidth = lineWidth+w;
                    cntxt.moveTo(zn[zcol].x, zn[zcol].y);
                }
                else if (zcol < zn.length-2) {
                    cntxt.lineTo(zn[zcol].x, zn[zcol].y);                
                }
                else {
                    cntxt.strokeStyle = color; 
                    cntxt.closePath();
                    cntxt.stroke();
                }            
            }
        }
    
        function clearCanvas(cntx){
            cntx.beginPath();
            cntx.clearRect(0, 0, width, height);
            cntx.fill();
        }
    
        Canvas {
            id: canvas 
            anchors.fill: parent
            objectName:"canvas"
            renderTarget: Canvas.FramebufferObject
            renderStrategy: Canvas.Cooperative
            state: "black"
     
            onPaint: {
                // Get drawing context
                var context = getContext("2d");
                clearCanvas(context);  // Make canvas all white
    
                var zlist = zoneOB.getZoneList;            
                // Draw zones
    	    for (var zrow in zlist) {
                    if ((zrow !=0 ) && (zrow !=1))
                    {
                        drawZone(context, zlist[zrow], zlist[zrow][5], 5); //zlist[zrow][5] );
                        drawZone(context, zlist[zrow], zlist[zrow][4], 0); //zlist[zrow][5] );  
                    }
                }         
            } //onPaint()
        } /* Canvas */
    
    
        Canvas {
            id: canvas0 
            anchors.fill: parent
            objectName:"canvas0"
            renderTarget: Canvas.FramebufferObject
            renderStrategy: Canvas.Cooperative
            state: "black"
            property real idx: 0 
            onPaint: {
                console.log("canvas 0");
                // Get drawing context
                var context = getContext("2d");
                clearCanvas(context);  // Make canvas all white
    
                var zlist = zoneOB.getZoneList;            
                if(zlist.length > idx)
                {
    		if(zlist[0][4]!= "OFF" && zlist[0][5]!="OFF")
                    {
                	    // Draw zone
                        drawZone(context, zlist[0], zlist[0][5], 5);
                        drawZone(context, zlist[0], zlist[0][4], 0);
                    }
                }
            } //onPaint()
        } /* Canvas */
    
        Canvas {
            id: canvas1 
            anchors.fill: parent
            objectName:"canvas1"
            renderTarget: Canvas.FramebufferObject
            renderStrategy: Canvas.Cooperative
            state: "black"
            property real idx: 1 
            onPaint: {
    console.log("canvas 1");
                // Get drawing context
                var context = getContext("2d");
                clearCanvas(context);  // Make canvas all white
    
                var zlist = zoneOB.getZoneList;            
                if(zlist.length > idx)
                {
    		if(zlist[1][4]!= "OFF" && zlist[1][5]!="OFF")
                    {
                	    // Draw zone
                        drawZone(context, zlist[1], zlist[1][5], 5);
                        drawZone(context, zlist[1], zlist[1][4], 0);
                    }
                }
            } //onPaint()
        } /* Canvas */
    
        Canvas {
            id: canvas2 
            anchors.fill: parent
            objectName:"canvas2"
            renderTarget: Canvas.FramebufferObject
            renderStrategy: Canvas.Cooperative
            state: "black"
            property real idx: 2 
            onPaint: {
    console.log("canvas 2");
                // Get drawing context
                var context = getContext("2d");
                clearCanvas(context);  // Make canvas all white
    
                var zlist = zoneOB.getZoneList;            
                if(zlist.length > idx)
                {
    		if(zlist[idx][4]!= "OFF" && zlist[idx][5]!="OFF")
                    {
                	    // Draw zone
                        drawZone(context, zlist[idx], zlist[idx][5], 5);
                        drawZone(context, zlist[idx], zlist[idx][4], 0);
                    }
                }
            } //onPaint()
        } /* Canvas */
    
        Canvas {
            id: canvas3 
            anchors.fill: parent
            objectName:"canvas3"
            renderTarget: Canvas.FramebufferObject
            renderStrategy: Canvas.Cooperative
            state: "black"
            property real idx: 3 
            onPaint: {
    console.log("canvas 3");
                // Get drawing context
                var context = getContext("2d");
                clearCanvas(context);  // Make canvas all white
    
                var zlist = zoneOB.getZoneList;            
                if(zlist.length > idx)
                {
    		if(zlist[idx][4]!= "OFF" && zlist[idx][5]!="OFF")
                    {
                	    // Draw zone
                        drawZone(context, zlist[idx], zlist[idx][5], 5);
                        drawZone(context, zlist[idx], zlist[idx][4], 0);
                    }
                }
            } //onPaint()
        } /* Canvas */
    
        Canvas {
            id: canvas4 
            anchors.fill: parent
            objectName:"canvas4"
            renderTarget: Canvas.FramebufferObject
            renderStrategy: Canvas.Cooperative
            state: "black"
            property real idx: 4 
            onPaint: {
    console.log("canvas 4");
                // Get drawing context
                var context = getContext("2d");
                clearCanvas(context);  // Make canvas all white
    
                var zlist = zoneOB.getZoneList;            
                if(zlist.length > idx)
                {
    		if(zlist[idx][4]!= "OFF" && zlist[idx][5]!="OFF")
                    {
                	    // Draw zone
                        drawZone(context, zlist[idx], zlist[idx][5], 5);
                        drawZone(context, zlist[idx], zlist[idx][4], 0);
                    }
                }
            } //onPaint()
        } /* Canvas */
    
        Canvas {
            id: canvas5 
            anchors.fill: parent
            objectName:"canvas5"
            renderTarget: Canvas.FramebufferObject
            renderStrategy: Canvas.Cooperative
            state: "black"
            property real idx: 5 
            onPaint: {
    console.log("canvas 5");
                // Get drawing context
                var context = getContext("2d");
                clearCanvas(context);  // Make canvas all white
    
                var zlist = zoneOB.getZoneList;            
                if(zlist.length > idx)
                {
    		if(zlist[idx][4]!= "OFF" && zlist[idx][5]!="OFF")
                    {
                	    // Draw zone
                        drawZone(context, zlist[idx], zlist[idx][5], 5);
                        drawZone(context, zlist[idx], zlist[idx][4], 0);
                    }
                }
            } //onPaint()
        } /* Canvas */
    
    
    
    
    
    }
    
    

  • Moderators

    hi @mxyn
    The Canvas element is probably the slowest way to draw stuff in QML. Quick to set up and nice for small details, but that's about it.

    The fastest, and probably most useful one for you is:
    Subclassing QQuickItem and using https://doc.qt.io/qt-5/qquickitem.html#updatePaintNode to draw directly onto the scene graph using OpenGL



  • @J-Hilk Please correct me if I'm wrong, but updatePaintNode would not allow me to only remove/modify one item from the scene without having to repaint the entire scene? So if I wanted to have multiple, independently drawn items, each item would have to be it's own QQuickItem?

    -Mercy


  • Moderators

    @mxyn as far as I understand it, that would be correct. however the update note function is super fast compared to canvas. I would first try everything inside one item



  • This post is deleted!

Log in to reply