Enable changing vertex and index counts after calling allocate() so
that it is not necessary to re-allocate memory to render a different
number of vertices.
Previously, it was only possible to change the number of vertices and
indices by calling allocate(). Resizing a geometry node with allocate()
is expensive: all vertex and index data must be re-initialized and
malloc() may need to find another memory block. If there are a large
number of vertices or indices, this takes a lot of processor cycles,
all during graph sync time while the main thread is blocked.
Two new functions, setVertexCount() and setIndexCount(), allow resizing
the geometry object without reallocating memory. The user is
responsible for ensuring that the requested counts do not exceed the
number originally allocated using allocate(). The usage pattern is
similar to QList::reserve(): allocate the maximum number of vertices or
indices that will be needed and call setVertexCount() or setIndexCount()
to set the counts to what is currently needed.
Consider the use case of drawing a heart rate monitor graph. The zigzag
tracing line of the graph continuously grows longer from left to right,
drawing new data without erasing old data until the line reaches the
right side of the graph area, then starting over from the left. As the
line grows, most data remains unchanged; the only vertices that need
modification are ones that are newly exposed by increasing the vertex
count.
The benchmark "tst_bench_qsggeometry" shows the difference on different
processors between resizing via allocate() and setVertexCount(), as in
the heart rate graph use case described above.
Vertices allocate() setVertexCount()
i.MX6 800 MHz 2-17K | 1.7 msecs | 7 μs
20K-37K | 6.0 msecs | 10 μs
40K-57K | 10.1 msecs | 16 μs
Intel i5-8265U 3.8Ghz 2-17K | 166 μs | 0.20 μs
20K-37K | 644 μs | 0.44 μs
40K-57K | 1134 μs | 0.85 μs
AMD 7945HX 5.5GHz 2-17K | 34 μs | 0.06 μs
20K-37K | 140 μs | 0.09 μs
40K-57K | 244 μs | 0.12 μs
The benchmark for allocate() is slow because allocate() calls malloc()
and updates all vertices each time the vertex count changes whereas
the benchmark for setVertexCount() only calls allocate() once and only
updates newly exposed vertices when the vertex count changes.
There are manual tests in the "manual/qsggeometry" folder which
exercise setVertexCount() and setIndexCount() by drawing a spiral
with thousands of vertices.
Task-number: QTBUG-126835
Change-Id: I5a0a6c68e3b5a17ffba914f1abb5078601bc4e05
Reviewed-by: Andy Nichols <andy.nichols@qt.io>