Solved 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 */ }
-
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
-
@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!