Alex
Alex

Reputation: 1175

Fast drawing lots of lines in Android Canvas: dealing with antialiasing and KitKat's peculiarities

I need to draw lots (~10k/frame is a common quantity) of lines fast. Known ways to draw those lines (single-threaded, antialiased):

Something tells me there is a couple of simple tricks to avoid both antialiasing and KitKat issues keeping the performance high

For the first one - is it possible, for example, to draw those lines not antialiased and then apply antialiasing to the whole bitmap (a variation of the fastest option)?

For the second - no ideas but some trimmer method dealing with NaNs. Anyway, KitKat is a relatively new and popular - there should be some solutions for its issues - otherwise the platform would be quite a headache to use

UPD2:
This question contains two separate issues:
- Antialiasing when using drawLines() with hardware acceleration and arbitrary (yet valid) input
- drawLines() refusing to draw anything on KitKat if the input contains NaNs

drawLines() is in focus because it is way faster than, for example, drawing the lines one by one using drawLine()

Also, the pictures below are the results of applying drawLines() two times to the same array:

canvas.drawLines(toDraw, 0, qty, paint);
canvas.drawLines(toDraw, 2, qty-4, paint); //qty % 4 == 0

UPD:
That's how the blur looks like. It's on the ends of the lines

Pic1

Upvotes: 2

Views: 1890

Answers (2)

Alex
Alex

Reputation: 1175

Well, the solution is just the result of what was written in chat (see Colt's post):

1) The original input array is split into pieces containing no NaNs
2) Those pieces are split so that maximum difference between line lengths in sub-pieces is less than 4x (experimentally obtained value). Applying drawLines() to the final sub-arrays results in no blur and rather good performance

Upvotes: 0

Colt McAnlis
Colt McAnlis

Reputation: 3886

There's a tangle of topics here; Let's try to unravel them.

Line "blurring"

Based on our chat, this issue only shows up once you start drawing line segments whose length < 1px. It's worth noting that drawLines() will tesselate all the line segments at one time, and likely the tessellator is falling over due to the presence of <1px lines in the set. This is the reason you're not seeing the "blurring" with using individual drawLine() commands; each drawLine() tessellates only the segment you've given it, so the errors are bound to just those super small segments (that are too small to see anyhow). The fix here is to add in some logic to remove the <1px length lines from your set, and this will fix the issue, and allow you to use drawLines() which is faster than the other methods.

NaNs issue

NaNs cause lots of problems on GPUs, so it makes sense that if they are included in your drawing list, that you would see problems. (much like the <1px line segments that are causing the blurring issues). Again, this is why you don't see visual problems using individual drawLine() commands; NaNs are breaking the tesselator, and isolating it only to those single segments, rather than the entire line list. Again the solution here would point to filtering the list to remove NaNs.

Performance

Given than the overhead of tessellating a line is significantly larger than a CPU check to discard a bad line, it would make sense that adding a pre process to remove the NaNs and <1px lines should be within your performance budget, and would remove the visual issues you're seeing.

Upvotes: 3

Related Questions