Quantcast
Channel: Qt DevNet forums: Qt Quick 1283365070**
Viewing all articles
Browse latest Browse all 4972

Canvases update: best practice and advices

$
0
0
Hi all, I’m developing an application which draws a series of 12 line graphs. The maximum number of points shown in each graph is equal to 300, i.e. I have at most about 3600 points showing in my GUI at the same time. I’ve investigated the usage of the canvas element as a solution to draw the points but I’m not sure that it can suite my needs. I’ve also come across several posts (here and on stackoverflow) which suggest to switch to other solutions (with better performances?) such as QPaintedItem or QQuickItem. Finally, I’ve also some doubts about the different options available for canvas items and how do they affect performances. Hence I’m sharing here my thoughts and my ideas, hoping to have a feedback from you, guys. Thanks in advance and sorry for the long post!! :) As said, the current naive implementation of the graphs is based on canvas elements. Behind each canvas is positioned a background image, i.e. the background grid of the graph is NOT painted by the canvas. Data come from a background thread (actually a pipeline of background threads); around 125 values per second per canvas are generated (1500 values overall). The thread emits a signal with the new data available and the signal is captured by each canvas. The array of floats is saved in a variant property (one for each canvas) and the paint code is called to “consume” the newly available data. The paint code should “filter” data belonging to the current canvas as the data chunk contains the points for ALL the canvases (the filter is omitted from the following code). Here is the code for the canvas item: Item {     id: chart     width: element.width     height: element.height     property string name;     property variant values;  // <--- stores data!!     property bool run;     property int interval;     property int offset: 0       function paintData()     {         canvas.counter = values.length / 8;                                               canvas.markDirty(Qt.rect(canvas.lastX, 35, canvas.counter, 160))         // <--- rectangular dirty area is smaller!!     }       Item {         id: element         x: 0         y: 0         width: 310         height: 176         anchors.centerIn: parent           Connections {             target: no  // <-- thread object               onReadData: {  // <-- signal readData(QList<float> data)                 values = data;  // <-- float values in the signature of the signal!                 paintData();    }                               }     Image {             id: background             width: 310             height: 160             source: "qrc:images/backTile.png"             fillMode: Image.Tile         }           Canvas {             id: canvas             y: 0             width: 310             height: 160             anchors.horizontalCenter: parent.horizontalCenter             contextType: "2d"             renderStrategy: Canvas.Cooperative             renderTarget: Canvas.FramebufferObject             canvasSize: Qt.size(310, 160)             tileSize: Qt.size(10, 160)             antialiasing: false             property real lastX: 0             property real lastY: 95             property int dataIndex: 0             property int counter: 0             property int arrayIndex: 0             x: 0               onPaint: {                 context.beginPath();                 context.moveTo(lastX, lastY);                 for(arrayIndex = offset; arrayIndex < counter; arrayIndex+=8)  // <--- take 1 value every 8                 {                     context.lineTo(++lastX, values[arrayIndex]);                     if(lastX == 310)                     {                         lastX = 0;                         context.clearRect (0, 0, width, height);   <                     }                 }                 //                 // stroke path                 context.stroke();                 if(lastX == 310)                 {                     lastX = 0;                     context.clearRect (0, 0, width, height);                 }             }         }     } } This solution works perfectly fine on PCs but fails to reach the required perfomances on tablets (tested on a Galaxy tab 2). In particular the graphs are rendered at 70% of the aspected speed. My goal is obviously to match the required performances ALSO on tablets with an hardware similar to galaxy tablets. Now, question time!! Canvas options(1): for what concerns “renderTarget” and “renderStrategy” what combination can best suite my needs? Probably it is me but docs does not help to shed a light on which combination I must prefer and why. Canvas options(2): what about “tileSize” and “canvasWindow” in my case? I didn’t notice any improvement in the usage of tiles: did I used them the wrong way? What would be the best way to pass data to the canvas instead of using the current approach? Emit a signal and let canvases directly read the thread array (registered as a property)? Using a Timer for reading the thread array? What if data is rendered in background to an image and it is loaded on each canvas by the backthread via a “loadImage()” call? Working on a background image should improve performances, shouldn’t it? Having several canvases concurrently calling their own paint routine is probably one of the biggest bottleneck. Is it possibile/feasible to have a unique paint routine for all the canvases? Does it make sense? Given the amount of data I’m managing, going for another solution (QQuickItem/QPaintedItem) can really improve the overall performance? If you reached this point…thanks for your time! Any advice/criticism/clarification/idea is really, really, REALLY appreciated! :)

Viewing all articles
Browse latest Browse all 4972