Great tool!
I noticed this is WinForms which is known for slow painting. The entire main window is invalidated and repaints when a new item is added. Two things I recommend updating to make a marked improvement:
A) turn on Double Buffering if not already. That may be enough. However, it may already be enabled.
B) since it's already ownerdrawn, save a bitmap in memory of the previously rendered result. Then, when new item is added, render a new bitmap to memory which contains just the new line (s). Then blt the bottom portion (with the top line(s) removed) from the existing previously used bitmap, and then blit just the new bottom lines which you already rendered in memory.
This results in eactly two blt operations (or one if you merge the two bitmaps first).
Essentially, you do your own double buffering, but you don't re-render with draw-calls what is already on the screen, you just "shift" it up or down.
The difference in draw performance will be substantial!
If you have any followup questions feel free to ask.
I just realized that this really isn't very clear. Essentially the idea is you are modifying the bitmap from the previous render each time you blast a new line in. The bitmap will remain the same size, but you do a block-copy to shift the elements up. Then you draw into the bitmap for the new line, then the on-screen update is just one draw of the entire bitmap.
Whenever the user resizes the window, you throw the bitmap away (well, not really, but you know what I mean it's data is no longer any good), and re-render all of the draw calls to the same bitmap, then just draw the bitmap once. It'll be all new data.
So the only time you'll have N draw calls is the first time, or after resize. Otherwise, you're just doing a bitmap data copy (which is relastively fast), and off-screen draw into that bitmap, and one then draw call to draw the entire bitmap to screen (that's the slow one, which is why we want to minimize the number of times we do it).
There is a more advanced algorithm that will avoid the large block transfer every update by doing offset rectangle drawing and contantly overwriting the items that have been pushed offscreen with the new item being added. This results in two bitmap renders to screen most updates (and 1 screen update every N lines where N is window height in lines), but you avoid the large block transfer to "shift" the items up. This is more complex, but possibly faster. For large windows / high resoultions, it could be considerably faster.
To visualize this algorithm, here's what initial 3 lines in the bitmap would look like for a window height of that can show 3 lines of text:
Line A
Line B
Line C
That is what is rendered to screen. The bitmap and what is seen on screen are the same.
You have a pointer at the top of the bitmap (ie the first line).
Then then the fourth line comes in, the bitmap is updated to this, but drawing over the line at the current pointer location (ie the first item):
Line D
Line B
Line C
The pointer is now shifted down a line to the second line.
Now you have to draw the above bitmap to screen in two draw calls. When you blt, you can provide a rectangle offset from the bitmap. Thus, you would render B and C in one draw call to the top of the target area, and then D in a second draw call to the area below. So on screen the user would see things in the correct order, although they are NOT in the correct order in the bitmap, and that's ok.
When another line comes in, the process repeats, and the bitmap becomes this:
Line D
Line E
Line C
Again, still two renders to get that bitmap to screen, but the first one is the last line, and the second render is the first two lines (again, keeping them order as we want to show C, D, and E).
And when the next line comes in, the bitmap now looks like this:
Line D
Line E
Line F
And one render will do it all, as things are already in the correct order just as they were when we started with A, B and C. The pointer is reset to the beginning top, and when G comes in, it overwrites D, and so forth.
So basically you avoid the large bit shift in memory each update, and instead roll through the buffer and keep overwriting the oldest line as a new one comes in. Whenever you are mid-buffer, you have to do two blt's to screen, but when you are at the end, you can do just one as everything is in order. So every Nth update, you only have one draw to screen. Most, you have two. BUT, you avoid the large data copy in memory.
You could implement both algorithms to see which is faster, but I believe both will be substiantally more efficient than what it is doing now (ie re-drawing each line one at a time to screen every update).
If you do implement both, I'd be very curious to see which is faster. ;-)
Last edit: Ryan Rogers 2019-07-24