Making Processing really scream: optimizing real time line drawing and scrolling

edited April 2014 in How To...

This question may be overly general, but: are there known tricks and techniques for making Processing run really fast?

In my case, I'm making a digital oscilloscope that reads a stream of sample data via a Client on port 5204. My goal is to display a scrolling waveform, and naturally I'd like to make the scrolling as smooth as possible, which means making the jumps as small as possible, which means maximizing the frame rate.

My environment: MacBook Pro (quad core) running OS X 10.9 (Mavericks), Processing 2.12.

In one thread, I read sample data from port 5204 and store the samples in a thread-safe FIFO. Then in my draw() routine I do this (schematically speaking):

draw() {
  if (new samples arrived in fifo) {
    discard fifo samples that have scrolled off the RHS;
    render_samples(fifo, offscreen_buffer);  // mostly a bunch of calls to offscreen_buffer.line(...);
  }
  image(offscreen_buffer, 0, 0);
}

One thing that comes to mind is that I could keep two offscreen buffers, each exactly as wide as the foreground screen. Rather than redrawing the entire offscreen buffer each time something has changed, I could add new lines to one offscreen buffer "right to left" and translate the underlying buffers when I render them to create the scrolling effect.

Any examples of that? And or other tricks I should know?

Thanks in advance.

Tagged:

Answers

  • Experiment with using PShape. Making multiple repeated calls to line function is called immediate mode rendering. It has a lot of overhead associated with actually performing the drawing operations.

    PShape would upload all of your vertex information to the GPU at once.

  • Bingo! PShape is eloquently described in this tutorial and appears to be perfect for my use case. Thanks for the pointer. (I'll let you know how much speedup I get!)

  • Alternatively... From your problem description it may also be possible to have a GLSL shader that side scrolls the image (aka moves everything one pixels to the left) and generates the last pixel column from the incoming value. Then you can call this shader on each separate incoming value in sequence, thus generating a moving image through the GPU.

  • As I think about it more, amnon's suggestion for a GLSL shader may be more appropriate here. The only possible complication is that I need to side-scroll by more than one pixel at a time (depending on screen update rate and rate at which new samples arrive). I'll mark this as answered and go experiment. Thanks for the tips.

  • You could also create and use a helper/background thread to handle the sampling and eliminate any delay from that.

  • What I've ended up doing is creating a collection of PGraphics "slices". I collect samples in a thread-safe FIFO (written to by the reader thread, read from by the drawing thread). Once the FIFO has collected enough to fill a slice, I empty the FIFO those samples into the slice and image() it onto my main screen, appropriately offset to create the scrolling effect.

    When the FIFO doesn't have enough samples to completely fill a slice, I write those samples into a slice (without emptying the FIFO) and render that at the left hand edge of my screen.

    Most of my overhead is making repeated calls to line(), but that's always less than one slice worth, so it's not much. All the other slices have been precomputed, so calling image() on them is fast.

    At any rate, I'm getting > 56 frames per second and it scrolls smoothly, so I don't feel the need to optimize it much more.

    Thanks for the suggestions.

Sign In or Register to comment.