简体   繁体   中英

How to invalidate screen faster?

In my current project (game of life) I need to redraw the screen as there are around 200 objects moving. I can think of two ways but have no clue which will be faster:

I can either:
1) Call Invalidate() for entire screen and in the Paint handler have following:

void Paint(object sender, PaintEventArgs e)
{
   foreach(Cell c in ListOfCells)
          {
             e.DrawImage(c,c.x,c.y);
          }
}

2)Or I could Invalidate each portion of screen for each cell:

public void MyInvalidate()
{
  foreach(Cell c in ListOfCells)
              {
                 Invalidate(c.X,c.Y,c.Width,c.Height);
              }


}

And have the same handler as above

Now, the first rule is always "Do not optimize prematurely". You need to be sure that you need that optimization over cleaner code.

Now, in a Game of Life, you're originally looking at a pretty empty screen. However, as the games goes on, more and more cells will be filled, eventually the whole board. Now the GOL rules dictate that most of these cells will change from one cycle to another.

You also need to understand what it means by "invalidating" a region. In Windows, invalidated regions "add up" to form a "update region" so that the WM_PAINT message can tell the program which portion(s) of the screen to be drawn. In your Paint event handler, you use RectVisible to determine whether a cell is to be refreshed.

In other words, the "cost" of doing method 1 (assuming board dimension n):

(n x n) x (redraw cell + update cell on screen)

Notice that I am assuming that you remember to do a clear screen before you paint the cells, otherwise the cells that used to be "alive" during the last cycle will stay on the screen. Thus this assumes that you are either drawing a live cell, or a blank cell, over the entire screen.

The "cost" of doing method 2:

(v) x (redraw cell + update cell on screen) + (n x n) x (RectVisible call)

where v = number of cells that changed (see caveat note below).

So, method 1 is faster than method 2 if:

(n x n) x redraw < v x redraw + (n x n) x RectVisible
n2 x (redraw - RectVisible) < v x redraw
v > ((redraw - RectVisible) / redraw) x n2
v > (1 - RectVisible/redraw) x n2

In other words, the number of changed cells must be larger than one minus the ratio of (RectVisible cost / redraw cost). Now, RectVisible is usually quite fast compared to drawing a bitmap onto the screen, especially if your cells are high resolution. Therefore, Rectvisible/redraw is usually a very small number, making method 1 faster than method 2 only when there are, say, >99% of the board changing at the same time, which is unlikely.

In other words, you'll find that method 2 usually yields higher performance, since DrawImage typically skips the whole operation if the image is to be drawn outside the clipping region (ie not within the update region).

CAVEAT - YOUR CODE AS IT IS WON'T WORK

However, your code in method 2 won't work. You have to remember to "blank out" the "dead" cells that used to have an "alive" cell during the last cycle. In other words, you invalidate the cells that "changed", not merely those that are "alive". Cells that are "alive" for multiple cycles do not need to be invalidated. Thus, the logic in your MyInvalidate method is flawed.

The second code won't do any good if you stick with the same Paint event handler you used for the first one, as basically you'll be redrawing ALL cells multiple times (because for each cell, you'll be redrawing all the other cells as well). To fix that, you could check e.ClipRectangle , and only redraw the cells that fall within that rectangle.

However, if the only thing you have on your screen are the cells (so you don't have a large number of other display elements, eg UI controls), then the first approach is the best you'll get (ie just Invalidate() the whole screen). Performance penalty only occurs when you're invalidating a LOT of otherwise unchanged areas of the screen.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM