Adding several PGraphics layers to the main canvas reduces performance A LOT

edited July 2016 in Questions about Code

Hi,

I am trying to do a drawing program with layers. Everytime the mouse is released a new layer is created for the next time it is pressed, and lines are painted. This mean that quickly i can generate a big amount of layers, each with 1500x1100.

My framerate is set to 60 FPS and with about 40 layers the performance is reduced to 10 FPS, which is unacceptable to this application (without layers the program runs without an itch at 60 FPS). I have another class handling the layers, and i add them to the main canvas like this:


public class Layer {
  PApplet p;
  PGraphics layer;
  float creationTime;
  float disapearTime;
  boolean startTransparency;
  
  public Layer(PApplet parent, int canvas_width, int canvas_height, float disapearTime) {
    this.p = parent;
    this.layer = p.createGraphics(canvas_width, canvas_height);
    this.disapearTime = disapearTime;
    startTransparency = false;
  }
  
  public PGraphics GetLayer(){
    return layer;
  }

for (int i=0 ; i < layers.size() ; i++){
    image(layers.get(i).GetLayer(), 0, 0);
}

Is this slowness expected behavior, is there something i can optimize? I'm thinking i don' really need 1500x1100 per layer since a continuous line will probably not be this big, and most of if is empty space, so i can for example create a smaller layer, but i am looking for a faster way to add/flatten the layers to the main canvas.

Answers

  • As I understand it, that loop is run each draw() iteration, even though it's gonna display the same thing until container layers gains or loses 1 of its PGraphics elements, is that so? :(|)

    Why don't you have a separate PGraphics which have that image() loop rendered into it once for each layers change? *-:)

    Perhaps except for the latest layers' PGraphics, since it's being actively modified.
    That tail 1 can be image() separately from the rest. :>

  • edited July 2016
    • In short, have 1 List<PGraphics> to store all past layers.
    • Have 1 PGraphics to keep the resultant rendering of all those past layers.
    • Plus 1 more PGraphics for the current active layer.
    • This way, you only need to image() 2 PGraphics instances within draw().
    • And only redo the resultant PGraphics when the List changes.
  • i tought that might be one of the options as well, but for the purpose i want i don't think it will work like that, let me explain and maybe you have a better plan. I want to simulate a Budah Board, were paint disappears overtime (and even other effects that also change over time like color). Therefore one layer is never really final because it keeps changing, either its opacity, color, shape. Can you think of a better way to do this? The performance hit is then expected, not caused by some bug in my code or in Processing?

    If you want you can take a look at the sketch and the layer class

  • edited July 2016
    • Do you really need to keep around 40+ Layer objects at the same time?
    • Can't you just get rid of the older 1s after a specified threshold?
    • Also tint() is absurdly slow!
    • Your code also needs some performance review.
    • I've spotted some places where things are unnecessarily done more than once.
  • Do you really need to keep around 40+ Layer objects at the same time?

    I don't want the user to have to deal with limitations of the program. I always try my best to disguise this and deal with them myself. The only solution i see is too blend old layers together, for example when the count is bigger then 40. I haven't started thinking of workarounds, until i am sure nothing more can be done without having to change the logic of the program.

    Can't you just get rid of the older 1s after a specified threshold?

    Thats what i do with the if (layers.get(i).GetTransparencyValue() > 0) . If the transparency is 0 then ignore it. But for example, think of an effect that doesn't end like "color intensity breathing", then this solution is not possible.

    Also tint() is absurdly slow!

    I noticed :o is there another faster solution to apply transparency to a canvas? I also wanted to use Tint for the color shift effect i mentioned.

    Your code also needs some performance review.

    I've been doing this on free time (which is not very stable). So indeed the code could use a big refactoring. That's why i was also asking if this slowness was a side effect from my programming or from Processing itself.

    So after this chitchat i'm guessing there is no better way to add layers on top of each other. I will have to find some workarounds, correct? What about a faster alternative to Tint?

  • edited July 2016 Answer ✓

    If the transparency is 0 then ignore it.

    It'd be much better if you simply get rid of them all. :>

    Only solution I see is to blend old layers together, for example when the count is bigger than 40.

    It's a good alternative to turn the older Layer objects into 1 PGraphics static background screenshot w/o any further manipulation. Still 40 threshold seems a tad too much though... :-SS

    Is there another faster solution to apply transparency to a canvas?

    Maybe some rect(0, 0, width, height); w/ a fill() w/ very low alpha.
    You can check it out this online fireworks example: :bz
    http://studio.ProcessingTogether.com/sp/pad/export/ro.9Q6oRai8-41WJ

  • edited July 2016 Answer ✓

    Some other additional considerations: *-:)

    • Replace JAVA2D w/ FX2D renderer for both the canvas and your PGraphics objects.
    • Iterate over your Layer objects from another Thread.
      That moves your Layer FXs away from sketch's main draw() callback.
  • Thanks, those are good tips! If you're curious about the project, this is what it does at the moment. LED Painting

    I use a LeapMotion to get the location of the finger or brush, send it to processing to generate an image, then serial to an Arduino that is controlling the LEDs. So you can see that 40 brush strokes to do a normal painting is not much

  • each with 1500x1100.

    could you store the LED array values rather than the canvases?

  • could you store the LED array values rather than the canvases?

    guess that is also something i can try, to do the addition manually. But i would not expect a bigger improvement compared to doing it with the PGraphics. But then again i didn't expect PGraphics to take that long.

Sign In or Register to comment.