UI objects JGraphics and Speed

AlexHarker's icon

Hello All,

I'm writing an object that plots a *lot* of points as a curve according to an analysis.

I would have assumed that the speed would be dependent on the number of points. However, what I'm finding is that if the data should happen to form a nice smooth curve then it's much faster than with less points with a very jagged curve. There is nothing in my end of the drawing code that would create this kind of result (As I've said I'd expect more points equals slower from my code).

1 - Is there some kind of simplification of the curve happening maybe (I'm repeatedly calling the lineto routine)?

2 - My data doesn't change very often. Is there a way of caching a full version somewhere and only drawing the bit that is being displayed (the axes of the display are variable)? Am I likely to see a speedup with this kind of approach, or is it possible that the matrix transforms built in to the graphics engine are the bottleneck?

Thanks

Alex

AlexHarker's icon

To add to this I just tried downsampling the curve so that when the points are closer than one point per pixel, I only draw two lines per visible pixel (by considering also the zoom factor and using the min/max values over the pixel to get the same shape as drawing everything). This doesn't seem to make it any faster, and shark see,s to indicate that most of the time is being spent in a juce call.

I'm sure there must be a better way to do this, as waveform~ etc. must do something like this and function fast enough. What I have not is super-slow for complex curves to an unusable degree.

Thanks for any help

Alex

Luigi Castelli's icon

Hi Alex,

I find this thread very interesting. Thanks for starting it...
I have been holding off replying because I wanted to see if someone from Cycling would chime in...

If you check out the Juce codebase you see that there is indeed some under-the-hood optimization which makes the amount of pixels that light up onscreen determine the overall drawing performance, not the number of points defining the underlining path. If you think about it, it makes sense: a path is just a mathematical definition of an entity that has no resemblance with anything physical, so the real work must happen when translating a path into pixels. Personally I think this is a desirable property. The same line could be defined by 2 points or by 200, however the drawing speed to render the line should not change.

...in any case, my experience is very similar to yours:

not long ago I tried implementing an object that would display a waveform with higher quality graphics than the waveform~ object does. (using border, antialiasing and gradients) The result was a huge speed difference between rendering a pretty smooth low-level waveform (less pixels to draw) and a high-level jagged (sometimes distorted) waveform (more pixels), where often times the slowness of the (re)drawing made the object unusable. Also, the redrawing speed was strongly influenced by the size of the object...
To make a long story short, my object ended up being practically unusable and I moved to something else...

Now...regarding waveform~, even though I have no access to the Cycling74 code, I am pretty sure the waveform~ object redraws itself fast enough because it doesn't feature any antialiasing. Consequently, it must use the jgraphics_line_draw_fast() function all over the place which is more limited but many times faster than a jgraphics_move_to()- jgraphics_line_to() combo.

I have to say that in my object I was drawing directly onscreen without any smart caching scheme.
I am sure that caching the curve in a surface or using layers would provide a substantial speed-up, but I haven't investigated that yet. I was gonna do it sooner or later. Maybe now it's the time...

Hit me up off-list if you are still interested. (superbigio-at-yahoo-dot-com)
Perhaps we can join our efforts.

Best.

- Luigi

AlexHarker's icon

Hi Luigi,

Thanks for this - I haven't chence to check everything you mention right now but I will do.

Actually I got things runing a *LOT* faster by drawing each part of the curve as a separate line (as in moveto / lineto for each one). So it seems the problem is with complex paths after all.... I had thought about the pixels thing too also, but really you should be able to draw a lot pixels on a screen fairly fast (it is 2011!).

Not sure if this helps you but it certainly got me to somewhere acceptable..

The jgraphics_line_draw_fast() tip is cool - I'll check that out also and try to report back but it might not be for a few weeks as I have other stuff to deal with right now...

A.ex

Timothy Place's icon

I definitely recommend using layers. For example, you can have your plot in a layer that is only invalidated when the points change or the size changes. This way you can reposition the object, lock/unlock the patcher, or change the background, etc. without having to redraw the data plot. There is an example in the "uioptimized" project in the sdk.

best,
Tim

AlexHarker's icon

Thanks Tim !!

Luigi Castelli's icon

@Alex:
that's very interesting...

So are you saying that this:

jgraphics_move_to(g, pt[0].x, pt[0].y);
for (i = 0; i < many; ++i) {
    jgraphics_move_to(g, pt[i].x, pt[i].y);
    jgraphics_stroke(g);
}

is a *LOT* faster than this?

jgraphics_move_to(g, pt[0].x, pt[0].y);
for (i = 0; i < many; ++i) {
    jgraphics_move_to(g, pt[i].x, pt[i].y);
}
jgraphics_stroke(g);

If that's the case, it could be that there is an optimal number of points between two jgraphics_stroke() calls that maximally optimizes drawing performances. Have you tested that?

@Tim:
Yes, layers seem definetely the way to go.
Thanks for the suggestion.

Best.

- Luigi

AlexHarker's icon

@Luigi:

---So are you saying that...

(I'm correcting your examples to these):

jgraphics_move_to(g, pt[0].x, pt[0].y);
for (i = 1; i < many; ++i) {
jgraphics_line_to(g, pt[i].x, pt[i].y);
jgraphics_stroke(g);
jgraphics_move_to(g, pt[i].x, pt[i].y);

(N.B the call to stroke clears the current position to (0,0).

jgraphics_move_to(g, pt[0].x, pt[0].y);
for (i = 1; i < many; ++i) {
jgraphics_line_to(g, pt[i].x, pt[i].y);
}
jgraphics_stroke(g);
}

For a complex path yes. I have no measurements for smooth paths, but for long paths it is difference between sitting and waiting for several seconds, and not sitting and waiting...

---Have you tested that?

No, but my assumption is that all seperate lines will be fastest (as the paths are all very straightforward). If you prove me wrong I'd be interessted to know about it.